Blocks and chunks

This commit is contained in:
2025-11-28 23:24:22 +01:00
parent 2541dee18d
commit 81a56f393e
32 changed files with 714 additions and 113 deletions

View File

@@ -6,6 +6,8 @@ const vk = @import("vulkan");
const math = @import("math.zig");
const Blocks = @import("assets/Blocks.zig");
const Chunk = @import("assets/Chunk.zig");
const Materials = @import("assets/Materials.zig");
const Textures = @import("assets/Textures.zig");
const CommandBuffer = @import("engine/CommandBuffer.zig").CommandBuffer;
@@ -58,7 +60,7 @@ const GlobalUniforms = extern struct {
}
};
const ObjectUniforms = extern struct {
pub const ObjectUniforms = extern struct {
matrixOStoWS: [16]f32,
matrixOStoWSNormal: [16]f32,
@@ -106,8 +108,7 @@ swapchain: *Swapchain,
global_descriptor_set_layout: vk.DescriptorSetLayout,
per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
descriptor_pool: vk.DescriptorPool,
/// [0] GLOBAL, [1] PER BATCH
descriptor_sets: [2]vk.DescriptorSet,
global_descriptor_set: vk.DescriptorSet,
pipeline_layout: vk.PipelineLayout,
pipeline: vk.Pipeline,
@@ -120,12 +121,12 @@ global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent),
global_uniforms_transfer_semaphores: []vk.Semaphore,
point_lights: PointLightBuffer,
directional_lights: DirectionalLightBuffer,
object_uniforms: ObjectUniformsBuffer,
sampler: vk.Sampler,
object_count: u32,
blocks: Blocks,
materials: Materials,
textures: Textures,
chunks: std.ArrayList(Chunk),
camera_position: Vector3 = .init(0, 0, 1.62),
camera_pitch: f32 = 0,
@@ -144,7 +145,7 @@ const max_directional_lights = 4;
const max_objects = 1024;
const camera_near_plane = 0.1;
const camera_vertical_fov_deg = 90.0;
const camera_vertical_fov_deg = 80.0;
const camera_half_vertical_fov_rad = 0.5 * camera_vertical_fov_deg * std.math.rad_per_deg;
const camera_mouse_sensitivity = 0.002;
@@ -158,7 +159,10 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
var textures = try Textures.init(engine, allocator);
errdefer textures.deinit(engine, allocator);
materials.loadAll(engine, &textures, allocator);
var blocks = try Blocks.init(allocator);
errdefer blocks.deinit(allocator);
blocks.loadAll(engine, &materials, &textures, allocator);
const sampler = try engine.createSampler(.{
.mag_filter = .linear,
@@ -359,13 +363,6 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
});
errdefer directional_lights.deinit(engine);
var object_uniforms = try ObjectUniformsBuffer.init(engine, .{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = max_objects,
});
errdefer object_uniforms.deinit(engine);
const pipeline = try engine.createGraphicsPipeline(.{
.stages = &.{
.{
@@ -484,7 +481,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
errdefer engine.destroyPipeline(pipeline);
const descriptor_pool = try engine.createDescriptorPool(.{
.max_sets = 2,
.max_sets = 1 + 256,
.pool_sizes = &.{
.{
.type = .sampler,
@@ -500,19 +497,17 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
},
.{
.type = .storage_buffer,
.descriptor_count = 4,
.descriptor_count = 3 + 256,
},
},
});
errdefer engine.destroyDescriptorPool(descriptor_pool);
// [0] GLOBAL, [1] PER BATCH
var descriptor_sets: [2]vk.DescriptorSet = undefined;
try engine.allocateDescriptorSets(.{
const global_descriptor_set = try engine.allocateDescriptorSet(.{
.descriptor_pool = descriptor_pool,
.set_layouts = &.{ global_descriptor_set_layout, per_batch_descriptor_set_layout },
.variable_descriptor_counts = &.{ @intCast(textures.textures.items.len), 0 },
}, &descriptor_sets);
.set_layout = global_descriptor_set_layout,
.variable_descriptor_count = @intCast(textures.textures.items.len),
});
const descriptor_images = try allocator.alloc(vk.DescriptorImageInfo, textures.textures.items.len);
for (textures.textures.items, descriptor_images) |texture, *info| {
@@ -527,7 +522,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
try engine.updateDescriptorSets(.{
.writes = &.{
.{
.dst_set = descriptor_sets[0],
.dst_set = global_descriptor_set,
.dst_binding = 0,
.dst_array_element = 0,
.descriptor_type = .uniform_buffer,
@@ -542,7 +537,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
},
},
.{
.dst_set = descriptor_sets[0],
.dst_set = global_descriptor_set,
.dst_binding = 1,
.dst_array_element = 0,
.descriptor_type = .storage_buffer,
@@ -557,7 +552,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
},
},
.{
.dst_set = descriptor_sets[0],
.dst_set = global_descriptor_set,
.dst_binding = 2,
.dst_array_element = 0,
.descriptor_type = .storage_buffer,
@@ -572,7 +567,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
},
},
.{
.dst_set = descriptor_sets[0],
.dst_set = global_descriptor_set,
.dst_binding = 3,
.dst_array_element = 0,
.descriptor_type = .storage_buffer,
@@ -587,52 +582,45 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
},
},
.{
.dst_set = descriptor_sets[0],
.dst_set = global_descriptor_set,
.dst_binding = 5,
.dst_array_element = 0,
.descriptor_type = .sampled_image,
.descriptor_infos = .{ .image = descriptor_images },
},
.{
.dst_set = descriptor_sets[1],
.dst_binding = 0,
.dst_array_element = 0,
.descriptor_type = .storage_buffer,
.descriptor_infos = .{
.buffer = &.{
.{
.buffer = object_uniforms.buffer,
.offset = 0,
.range = vk.WHOLE_SIZE,
},
},
},
},
},
});
const point_lights_data: []const PointLight = &.{
.{
.positionWS = .{ 0, 0, 0.5 },
.color = .{ 1, 1, 1 },
},
.{
.positionWS = .{ -5, 5, 0.5 },
.color = .{ 1, 0, 0 },
},
.{
.positionWS = .{ 5, 5, 0.5 },
.color = .{ 0, 0, 1 },
},
.{
.positionWS = .{ -5, -5, 0.5 },
.color = .{ 0, 1, 0 },
},
.{
.positionWS = .{ 5, -5, 0.5 },
.color = .{ 1, 1, 0 },
},
};
var chunks: std.ArrayList(Chunk) = .empty;
errdefer {
for (chunks.items) |*chunk| {
chunk.deinit(engine, descriptor_pool);
}
chunks.deinit(allocator);
}
var it: Iterator3 = .init(.init(-64, -64, 0), .init(64, 64, 0), .init(16, 16, 16));
while (it.next()) |origin| {
try chunks.ensureUnusedCapacity(allocator, 1);
chunks.appendAssumeCapacity(try Chunk.init(engine, .{
.origin = origin,
.descriptor_pool = descriptor_pool,
.per_batch_descriptor_set_layout = per_batch_descriptor_set_layout,
}));
const chunk = &chunks.items[chunks.items.len - 1];
var it2 = Iterator3.init(.init(0, 0, 0), .init(1, 1, 0), .{ .vector = @splat(1.0 / 16.0) });
while (it2.next()) |fpos| {
const x, const y, const z = fpos.asArrayNorm(u4);
const block: Blocks.Id = @enumFromInt(engine.random.intRangeLessThan(u12, 1, @intCast(blocks.blocks.items.len)));
chunk.blocks[z][y][x] = block;
}
try chunk.refresh(engine, &blocks, allocator);
}
const point_lights_data: []const PointLight = &.{};
try point_lights.write(engine, .{
.header = @intCast(point_lights_data.len),
.elements = point_lights_data,
@@ -649,26 +637,6 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
.elements = directional_lights_data,
});
const object_count: u32 = blk: {
var objects: std.ArrayList(ObjectUniforms) = try .initCapacity(allocator, 578);
defer objects.deinit(allocator);
var it = Iterator3.init(.init(-8, -8, 0), .init(8, 8, 2), .init(1, 1, 2));
while (it.next()) |pos| {
const material: Materials.Id = @enumFromInt(engine.random.uintLessThan(u16, @intFromEnum(materials.next_id)));
const matrix_os_to_ws = Matrix4x4.initTranslation(pos);
const matrix_os_to_ws_normal = Matrix4x4.inverseTransposeAffine(matrix_os_to_ws);
objects.appendAssumeCapacity(.{
.matrixOStoWS = matrix_os_to_ws.asArray(),
.matrixOStoWSNormal = matrix_os_to_ws_normal.asArray(),
.material = material,
});
}
try object_uniforms.write(engine, .{ .elements = objects.items });
break :blk @intCast(objects.items.len);
};
return .{
.allocator = allocator,
.engine = engine,
@@ -676,7 +644,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
.global_descriptor_set_layout = global_descriptor_set_layout,
.per_batch_descriptor_set_layout = per_batch_descriptor_set_layout,
.descriptor_pool = descriptor_pool,
.descriptor_sets = descriptor_sets,
.global_descriptor_set = global_descriptor_set,
.pipeline_layout = pipeline_layout,
.pipeline = pipeline,
@@ -689,12 +657,12 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
.point_lights = point_lights,
.directional_lights = directional_lights,
.object_uniforms = object_uniforms,
.sampler = sampler,
.object_count = object_count,
.blocks = blocks,
.materials = materials,
.textures = textures,
.chunks = chunks,
};
}
@@ -703,13 +671,16 @@ pub fn deinit(self: *Game) void {
self.vertex_buffer.deinit(self.engine);
self.index_buffer.deinit(self.engine);
for (self.chunks.items) |*chunk| {
chunk.deinit(self.engine, self.descriptor_pool);
}
self.chunks.deinit(self.allocator);
self.global_uniforms.deinit(self.engine);
self.global_uniforms_staging_buffer.deinit(self.engine);
self.global_uniforms_transfer_command_buffer.deinit(self.engine);
self.point_lights.deinit(self.engine);
self.directional_lights.deinit(self.engine);
self.object_uniforms.deinit(self.engine);
for (self.global_uniforms_transfer_semaphores) |semaphore| {
self.engine.destroySemaphore(semaphore);
@@ -725,6 +696,7 @@ pub fn deinit(self: *Game) void {
self.textures.deinit(self.engine, self.allocator);
self.materials.deinit(self.engine, self.allocator);
self.blocks.deinit(self.allocator);
self.* = undefined;
}
@@ -768,7 +740,7 @@ pub fn update(self: *Game, dt: f32) void {
);
// zig fmt: on
const ambient_light = Vector3.init(0.2, 0.2, 0.2);
const ambient_light = Vector3.init(0.001, 0.001, 0.001);
const global_uniforms_data: GlobalUniforms = .{
.matrixWStoVS = matrix_ws_to_vs.asArray(),
@@ -926,12 +898,11 @@ fn render(self: *Game) !void {
},
});
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
command_buffer.bindDescriptorSets(.graphics, self.pipeline_layout, 0, &self.descriptor_sets, &.{});
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.global_descriptor_set, null);
command_buffer.drawIndexed(.{
.index_count = self.index_buffer.array_capacity,
.instance_count = self.object_count,
});
for (self.chunks.items) |chunk| {
chunk.draw(self.pipeline_layout, command_buffer);
}
}
try command_buffer.endCommandBuffer();