Perspective projection
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 fragCoord;
|
||||
layout(location = 1) in float vertexIndex;
|
||||
layout(location = 0) in float vertexIndex;
|
||||
layout(location = 1) in float depth;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(fragCoord.z, vertexIndex * 0.1, 0.0, 1.0);
|
||||
fragColor = vec4(
|
||||
depth,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
);
|
||||
}
|
||||
|
@@ -1,11 +1,20 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inCoord;
|
||||
layout(location = 0) out vec3 outCoord;
|
||||
layout(location = 1) out float vertexIndex;
|
||||
layout(location = 0) out float vertexIndex;
|
||||
layout(location = 1) out float depth;
|
||||
|
||||
layout(set = 1, binding = 0) uniform Camera{
|
||||
mat4 transform;
|
||||
} camera;
|
||||
layout(set = 1, binding = 1) uniform Object{
|
||||
mat4 transform;
|
||||
} object;
|
||||
|
||||
|
||||
void main() {
|
||||
outCoord = inCoord * 0.5 + 0.5;
|
||||
vertexIndex = gl_VertexIndex;
|
||||
gl_Position = vec4(inCoord, 1.0);
|
||||
vec4 outPos = vec4(inCoord, 1.0) * object.transform * camera.transform;
|
||||
depth = outPos.z / outPos.w;
|
||||
gl_Position = outPos;
|
||||
}
|
||||
|
103
src/graphics.zig
103
src/graphics.zig
@@ -1,5 +1,8 @@
|
||||
const std = @import("std");
|
||||
const sdl = @import("sdl");
|
||||
const presets = @import("graphics/presets.zig");
|
||||
const Transform = @import("graphics/transform.zig");
|
||||
const Camera = @import("graphics/camera.zig");
|
||||
const GameError = @import("game.zig").GameError;
|
||||
|
||||
window: *sdl.Window,
|
||||
@@ -18,6 +21,23 @@ pipeline: *sdl.GPUGraphicsPipeline,
|
||||
|
||||
to_resize: ?struct { u32, u32 } = null,
|
||||
|
||||
const MESH_BYTES = MESH.len * 4;
|
||||
const MESH_VERTS = @divExact(MESH.len, 3);
|
||||
const MESH = [_]f32{
|
||||
-1, 0, 4,
|
||||
0, 1, 4,
|
||||
1, -1, 6,
|
||||
1, 0, 4,
|
||||
0, -1, 4,
|
||||
-1, 1, 6,
|
||||
-1, 1, 6,
|
||||
1, 1, 6,
|
||||
-1, -1, 6,
|
||||
1, -1, 6,
|
||||
-1, -1, 6,
|
||||
1, 1, 6,
|
||||
};
|
||||
|
||||
const Self = @This();
|
||||
pub fn create() GameError!Self {
|
||||
// Init
|
||||
@@ -28,7 +48,7 @@ pub fn create() GameError!Self {
|
||||
var window: ?*sdl.Window = null;
|
||||
|
||||
if (!sdl.CreateWindowAndRenderer(
|
||||
"Spacefarer",
|
||||
"",
|
||||
1600,
|
||||
900,
|
||||
sdl.WINDOW_VULKAN | sdl.WINDOW_RESIZABLE,
|
||||
@@ -55,26 +75,35 @@ pub fn create() GameError!Self {
|
||||
const shader_vert = try loadShader(
|
||||
device,
|
||||
"data/shaders/basic.vert",
|
||||
sdl.GPU_SHADERSTAGE_VERTEX,
|
||||
.{
|
||||
.entrypoint = "main",
|
||||
.format = sdl.GPU_SHADERFORMAT_SPIRV,
|
||||
.stage = sdl.GPU_SHADERSTAGE_VERTEX,
|
||||
.num_uniform_buffers = 2,
|
||||
},
|
||||
);
|
||||
errdefer sdl.ReleaseGPUShader(device, shader_vert);
|
||||
|
||||
const shader_frag = try loadShader(
|
||||
device,
|
||||
"data/shaders/basic.frag",
|
||||
sdl.GPU_SHADERSTAGE_FRAGMENT,
|
||||
.{
|
||||
.entrypoint = "main",
|
||||
.format = sdl.GPU_SHADERFORMAT_SPIRV,
|
||||
.stage = sdl.GPU_SHADERSTAGE_FRAGMENT,
|
||||
},
|
||||
);
|
||||
errdefer sdl.ReleaseGPUShader(device, shader_frag);
|
||||
|
||||
const vertex_buffer = sdl.CreateGPUBuffer(device, &.{
|
||||
.usage = sdl.GPU_BUFFERUSAGE_VERTEX,
|
||||
// 6 Vertices * 3 Coordinates * 4 Bytes
|
||||
.size = 6 * 3 * 4,
|
||||
// Vertices * 3 Coordinates * 4 Bytes
|
||||
.size = MESH_BYTES,
|
||||
}) orelse return GameError.SdlError;
|
||||
errdefer sdl.ReleaseGPUBuffer(device, vertex_buffer);
|
||||
|
||||
const transfer_buffer = sdl.CreateGPUTransferBuffer(device, &.{
|
||||
.size = 6 * 3 * 4,
|
||||
.size = MESH_BYTES,
|
||||
.usage = sdl.GPU_TRANSFERBUFFERUSAGE_UPLOAD,
|
||||
}) orelse return GameError.SdlError;
|
||||
defer sdl.ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||
@@ -82,16 +111,7 @@ pub fn create() GameError!Self {
|
||||
{ // Filling up transfer buffer
|
||||
const mapped_buffer: [*c]f32 = @alignCast(@ptrCast(sdl.MapGPUTransferBuffer(device, transfer_buffer, false) orelse return GameError.SdlError));
|
||||
defer sdl.UnmapGPUTransferBuffer(device, transfer_buffer);
|
||||
std.mem.copyForwards(f32, mapped_buffer[0 .. 6 * 3], &[6 * 3]f32{
|
||||
// Triangle 1
|
||||
-1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
1.0, -1.0, 1.0,
|
||||
// Triangle 2
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
});
|
||||
std.mem.copyForwards(f32, mapped_buffer[0..MESH.len], &MESH);
|
||||
}
|
||||
|
||||
{ // Copying data over from transfer buffer to vertex buffer
|
||||
@@ -99,7 +119,7 @@ pub fn create() GameError!Self {
|
||||
const copy_pass = sdl.BeginGPUCopyPass(command_buffer) orelse return GameError.SdlError;
|
||||
|
||||
sdl.UploadToGPUBuffer(copy_pass, &.{ .transfer_buffer = transfer_buffer }, &.{
|
||||
.size = 6 * 3 * 4,
|
||||
.size = MESH_BYTES,
|
||||
.buffer = vertex_buffer,
|
||||
}, false);
|
||||
|
||||
@@ -141,33 +161,16 @@ pub fn create() GameError!Self {
|
||||
.num_vertex_attributes = 1,
|
||||
},
|
||||
.primitive_type = sdl.GPU_PRIMITIVETYPE_TRIANGLELIST,
|
||||
.rasterizer_state = .{
|
||||
.cull_mode = sdl.GPU_CULLMODE_BACK,
|
||||
.fill_mode = sdl.GPU_FILLMODE_FILL,
|
||||
.front_face = sdl.GPU_FRONTFACE_CLOCKWISE,
|
||||
},
|
||||
.rasterizer_state = presets.RASTERIZER_CULL,
|
||||
.multisample_state = .{
|
||||
.sample_count = sdl.GPU_SAMPLECOUNT_4,
|
||||
},
|
||||
.depth_stencil_state = .{
|
||||
.compare_op = sdl.GPU_COMPAREOP_LESS,
|
||||
.enable_depth_test = true,
|
||||
.enable_depth_write = true,
|
||||
},
|
||||
.depth_stencil_state = presets.DEPTH_ENABLED,
|
||||
.target_info = .{
|
||||
.depth_stencil_format = sdl.GPU_TEXTUREFORMAT_D16_UNORM,
|
||||
.color_target_descriptions = &sdl.GPUColorTargetDescription{
|
||||
.format = target_format,
|
||||
.blend_state = .{
|
||||
.enable_blend = true,
|
||||
.alpha_blend_op = sdl.GPU_BLENDOP_ADD,
|
||||
.color_blend_op = sdl.GPU_BLENDOP_ADD,
|
||||
.color_write_mask = sdl.GPU_COLORCOMPONENT_R | sdl.GPU_COLORCOMPONENT_G | sdl.GPU_COLORCOMPONENT_B | sdl.GPU_COLORCOMPONENT_A,
|
||||
.src_alpha_blendfactor = sdl.GPU_BLENDFACTOR_ONE,
|
||||
.src_color_blendfactor = sdl.GPU_BLENDFACTOR_SRC_ALPHA,
|
||||
.dst_alpha_blendfactor = sdl.GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.dst_color_blendfactor = sdl.GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
},
|
||||
.blend_state = presets.BLEND_NORMAL,
|
||||
},
|
||||
.num_color_targets = 1,
|
||||
.has_depth_stencil_target = true,
|
||||
@@ -245,7 +248,18 @@ pub fn drawDebug(self: *Self) GameError!void {
|
||||
|
||||
sdl.BindGPUGraphicsPipeline(render_pass, self.pipeline);
|
||||
sdl.BindGPUVertexBuffers(render_pass, 0, &.{ .offset = 0, .buffer = self.vertex_buffer }, 1);
|
||||
sdl.DrawGPUPrimitives(render_pass, 6, 1, 0, 0);
|
||||
const transform = Transform{};
|
||||
const camera = Camera{
|
||||
.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.EndGPURenderPass(render_pass);
|
||||
}
|
||||
@@ -255,20 +269,17 @@ pub fn endDraw(self: *Self) GameError!void {
|
||||
if (!sdl.SubmitGPUCommandBuffer(self.command_buffer)) return GameError.SdlError;
|
||||
}
|
||||
|
||||
fn loadShader(device: *sdl.GPUDevice, path: []const u8, stage: c_uint) GameError!*sdl.GPUShader {
|
||||
fn loadShader(device: *sdl.GPUDevice, path: []const u8, info: sdl.GPUShaderCreateInfo) GameError!*sdl.GPUShader {
|
||||
const file = std.fs.cwd().openFile(path, .{}) catch return GameError.OSError;
|
||||
defer file.close();
|
||||
|
||||
const code = file.readToEndAllocOptions(std.heap.c_allocator, 1024 * 1024 * 1024, null, @alignOf(u8), 0) catch return GameError.OSError;
|
||||
defer std.heap.c_allocator.free(code);
|
||||
|
||||
return sdl.CreateGPUShader(device, &.{
|
||||
.code = code,
|
||||
.code_size = code.len,
|
||||
.entrypoint = "main",
|
||||
.format = sdl.GPU_SHADERFORMAT_SPIRV,
|
||||
.stage = stage,
|
||||
}) orelse return GameError.SdlError;
|
||||
var updated_info = info;
|
||||
updated_info.code = code;
|
||||
updated_info.code_size = code.len;
|
||||
return sdl.CreateGPUShader(device, &updated_info) orelse return GameError.SdlError;
|
||||
}
|
||||
|
||||
fn createDepthTexture(device: *sdl.GPUDevice, width: u32, height: u32) GameError!*sdl.GPUTexture {
|
||||
|
24
src/graphics/camera.zig
Normal file
24
src/graphics/camera.zig
Normal file
@@ -0,0 +1,24 @@
|
||||
const std = @import("std");
|
||||
const sdl = @import("sdl");
|
||||
const Transform = @import("transform.zig");
|
||||
const Camera = @This();
|
||||
|
||||
transform: Transform,
|
||||
lens: @Vector(2, f32),
|
||||
near: f32,
|
||||
far: f32,
|
||||
|
||||
pub fn matrix(camera: Camera) @Vector(16, f32) {
|
||||
const xx = 1.0 / camera.lens[0];
|
||||
const yy = 1.0 / camera.lens[1];
|
||||
const fnmod = 1.0 / (camera.far - camera.near);
|
||||
const zz = camera.far * fnmod;
|
||||
const wz = -camera.near * camera.far * fnmod;
|
||||
const projection = @Vector(16, f32){
|
||||
xx, 0, 0, 0,
|
||||
0, yy, 0, 0,
|
||||
0, 0, zz, wz,
|
||||
0, 0, 1, 0,
|
||||
};
|
||||
return Transform.multiplyMatrix(projection, camera.transform.inverse());
|
||||
}
|
24
src/graphics/presets.zig
Normal file
24
src/graphics/presets.zig
Normal file
@@ -0,0 +1,24 @@
|
||||
const sdl = @import("sdl");
|
||||
|
||||
pub const BLEND_NORMAL = sdl.GPUColorTargetBlendState{
|
||||
.enable_blend = true,
|
||||
.alpha_blend_op = sdl.GPU_BLENDOP_ADD,
|
||||
.color_blend_op = sdl.GPU_BLENDOP_ADD,
|
||||
.color_write_mask = sdl.GPU_COLORCOMPONENT_R | sdl.GPU_COLORCOMPONENT_G | sdl.GPU_COLORCOMPONENT_B | sdl.GPU_COLORCOMPONENT_A,
|
||||
.src_alpha_blendfactor = sdl.GPU_BLENDFACTOR_ONE,
|
||||
.src_color_blendfactor = sdl.GPU_BLENDFACTOR_SRC_ALPHA,
|
||||
.dst_alpha_blendfactor = sdl.GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.dst_color_blendfactor = sdl.GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
};
|
||||
|
||||
pub const DEPTH_ENABLED = sdl.GPUDepthStencilState{
|
||||
.compare_op = sdl.GPU_COMPAREOP_LESS,
|
||||
.enable_depth_test = true,
|
||||
.enable_depth_write = true,
|
||||
};
|
||||
|
||||
pub const RASTERIZER_CULL = sdl.GPURasterizerState{
|
||||
.cull_mode = sdl.GPU_CULLMODE_BACK,
|
||||
.fill_mode = sdl.GPU_FILLMODE_FILL,
|
||||
.front_face = sdl.GPU_FRONTFACE_CLOCKWISE,
|
||||
};
|
53
src/graphics/transform.zig
Normal file
53
src/graphics/transform.zig
Normal file
@@ -0,0 +1,53 @@
|
||||
const std = @import("std");
|
||||
const Transform = @This();
|
||||
|
||||
// TODO: Rotation
|
||||
|
||||
position: @Vector(3, f32) = @splat(0.0),
|
||||
rotation: @Vector(3, f32) = @splat(0.0),
|
||||
scale: @Vector(3, f32) = @splat(1.0),
|
||||
|
||||
pub fn matrix(transform: Transform) @Vector(16, f32) {
|
||||
return .{
|
||||
1.0, 0.0, 0.0, transform.position[0],
|
||||
0.0, 1.0, 0.0, transform.position[1],
|
||||
0.0, 0.0, 1.0, transform.position[2],
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn inverse(transform: Transform) @Vector(16, f32) {
|
||||
// TODO: Could we just translate, rotate and scale back instead of relying on matrix math?
|
||||
return invertMatrix(transform.matrix());
|
||||
}
|
||||
|
||||
fn invertMatrix(a: @Vector(16, f32)) @Vector(16, f32) {
|
||||
const MOD: f32 = 1.0 / 16.0;
|
||||
const ID = @Vector(16, f32){
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
var p = ID - @as(@Vector(16, f32), @splat(MOD)) * a;
|
||||
var output = ID + p;
|
||||
inline for (0..8) |_| {
|
||||
p = multiplyMatrix(p, p);
|
||||
output = multiplyMatrix(output, ID + p);
|
||||
}
|
||||
return output * @as(@Vector(16, f32), @splat(MOD));
|
||||
}
|
||||
|
||||
pub fn multiplyMatrix(a: @Vector(16, f32), b: @Vector(16, f32)) @Vector(16, f32) {
|
||||
var output: @Vector(16, f32) = [1]f32{0.0} ** 16;
|
||||
|
||||
@setFloatMode(.optimized);
|
||||
for (0..4) |row| {
|
||||
for (0..4) |col| {
|
||||
for (0..4) |i| {
|
||||
output[row * 4 + col] += a[row * 4 + i] * b[i * 4 + col];
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
Reference in New Issue
Block a user