Eliminate opposing walls

This commit is contained in:
2025-11-29 14:49:28 +01:00
parent 8d07dcd594
commit 5dfbc64676
4 changed files with 226 additions and 130 deletions

View File

@@ -10,6 +10,8 @@ const CommandBuffer = @import("../engine/CommandBuffer.zig").CommandBuffer;
const Engine = @import("../engine/Engine.zig");
const Game = @import("../Game.zig");
const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer;
const Materials = @import("Materials.zig");
const Orientation = @import("../voxel.zig").Orientation;
const Matrix4x4 = math.Matrix4x4;
const ObjectUniformsBuffer = GenericBuffer(void, Game.ObjectUniforms);
@@ -20,11 +22,15 @@ pub const chunk_size = 16;
const initial_capacity = 256;
var next_chunk_id: std.atomic.Value(u64) = .init(0);
/// To get the block at coordinates (x, y, z) relative to the chunk, read the
/// value at `blocks[z][y][x]`.
blocks: [chunk_size][chunk_size][chunk_size]Blocks.Id,
origin: Vector3,
descriptor_set: vk.DescriptorSet,
object_buffer: ObjectUniformsBuffer,
object_count: u32,
/// For debug purposes, a unique "name" per chunk instance.
chunk_id: u64,
pub const InitInfo = struct {
@@ -33,6 +39,15 @@ pub const InitInfo = struct {
per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
};
pub const Neighbors = struct {
positive_x: ?*const Chunk,
negative_x: ?*const Chunk,
positive_y: ?*const Chunk,
negative_y: ?*const Chunk,
positive_z: ?*const Chunk,
negative_z: ?*const Chunk,
};
pub fn init(engine: *Engine, init_info: InitInfo) !Chunk {
const descriptor_set = try engine.allocateDescriptorSet(.{
.descriptor_pool = init_info.descriptor_pool,
@@ -89,23 +104,97 @@ pub fn deinit(self: *Chunk, engine: *Engine, descriptor_pool: vk.DescriptorPool)
self.* = undefined;
}
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, temp_allocator: std.mem.Allocator) !void {
var object_count: u32 = 0;
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors: Neighbors, temp_allocator: std.mem.Allocator) !void {
var uniforms: std.ArrayList(Game.ObjectUniforms) = try .initCapacity(temp_allocator, initial_capacity);
defer uniforms.deinit(temp_allocator);
for (self.blocks) |plane| {
for (plane) |row| {
for (row) |id| {
for (self.blocks, 0..) |plane, iz| {
const fz: f32 = @floatFromInt(iz);
for (plane, 0..) |row, iy| {
const fy: f32 = @floatFromInt(iy);
for (row, 0..) |id, ix| {
const fx: f32 = @floatFromInt(ix);
const block = blocks.getBlock(id).?;
object_count += @intFromBool(block.positive_x != .empty);
object_count += @intFromBool(block.negative_x != .empty);
object_count += @intFromBool(block.positive_y != .empty);
object_count += @intFromBool(block.negative_y != .empty);
object_count += @intFromBool(block.positive_z != .empty);
object_count += @intFromBool(block.negative_z != .empty);
const center = Vector3.add(self.origin, .init(fx, fy, fz));
const cx, const cy, const cz = center.asArray();
if (block.positive_x != .empty and self.getOpposite(.positive_x, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
0, 1, 0, 0,
0, 0, 1, 0,
1, 0, 0, 0,
cx + 0.5, cy, cz, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_x));
}
if (block.negative_x != .empty and self.getOpposite(.negative_x, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
0, -1, 0, 0,
0, 0, 1, 0,
-1, 0, 0, 0,
cx - 0.5, cy, cz, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_x));
}
if (block.positive_y != .empty and self.getOpposite(.positive_y, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
-1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0,
cx, cy + 0.5, cz, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_y));
}
if (block.negative_y != .empty and self.getOpposite(.negative_y, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, 0, 1, 0,
0, -1, 0, 0,
cx, cy - 0.5, cz, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_y));
}
if (block.positive_z != .empty and self.getOpposite(.positive_z, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
cx, cy, cz + 0.5, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_z));
}
if (block.negative_z != .empty and self.getOpposite(.negative_z, ix, iy, iz, blocks, neighbors) == .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, -1, 0,
cx, cy, cz - 0.5, 1,
);
// zig fmt: on
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_z));
}
}
}
}
const object_count: u32 = @intCast(uniforms.items.len);
if (self.object_buffer.array_capacity < object_count) {
const desired_capacity = std.math.ceilPowerOfTwoAssert(u32, object_count);
const new_object_buffer: ObjectUniformsBuffer = try .init(engine, .{
@@ -140,105 +229,7 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, temp_alloca
engine.setObjectName(new_object_buffer.device_memory, "DM Chunk[{d}]", .{self.chunk_id});
}
const uniforms = try temp_allocator.alloc(Game.ObjectUniforms, object_count);
var object_i: usize = 0;
defer temp_allocator.free(uniforms);
for (self.blocks, 0..) |plane, iz| {
const fz: f32 = @floatFromInt(iz);
for (plane, 0..) |row, iy| {
const fy: f32 = @floatFromInt(iy);
for (row, 0..) |id, ix| {
const fx: f32 = @floatFromInt(ix);
const block = blocks.getBlock(id).?;
const center = Vector3.add(self.origin, .init(fx, fy, fz));
const cx, const cy, const cz = center.asArray();
if (block.positive_x != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
0, 1, 0, 0,
0, 0, 1, 0,
1, 0, 0, 0,
cx + 0.5, cy, cz, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.positive_x);
object_i += 1;
}
if (block.negative_x != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
0, -1, 0, 0,
0, 0, 1, 0,
-1, 0, 0, 0,
cx - 0.5, cy, cz, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.negative_x);
object_i += 1;
}
if (block.positive_y != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
-1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0,
cx, cy + 0.5, cz, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.positive_y);
object_i += 1;
}
if (block.negative_y != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, 0, 1, 0,
0, -1, 0, 0,
cx, cy - 0.5, cz, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.negative_y);
object_i += 1;
}
if (block.positive_z != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
cx, cy, cz + 0.5, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.positive_z);
object_i += 1;
}
if (block.negative_z != .empty) {
// zig fmt: off
const matrix: Matrix4x4 = .init(
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, -1, 0,
cx, cy, cz - 0.5, 1,
);
// zig fmt: on
uniforms[object_i] = .init(matrix, matrix, block.negative_z);
object_i += 1;
}
}
}
}
std.debug.assert(object_i == uniforms.len);
try self.object_buffer.write(engine, .{ .elements = uniforms });
try self.object_buffer.write(engine, .{ .elements = uniforms.items });
self.object_count = object_count;
}
@@ -246,3 +237,44 @@ pub fn draw(self: *const Chunk, layout: vk.PipelineLayout, command_buffer: Comma
command_buffer.bindDescriptorSets(.graphics, layout, 1, &.{self.descriptor_set}, &.{});
command_buffer.drawIndexed(.{ .index_count = 6, .instance_count = self.object_count });
}
fn getOpposite(self: *const Chunk, comptime side: Orientation, x: usize, y: usize, z: usize, blocks: *const Blocks, neighbors: Neighbors) Materials.Id {
return switch (side) {
.positive_x => if (x + 1 < chunk_size)
blocks.getBlock(self.blocks[z][y][x + 1]).?.negative_x
else if (neighbors.positive_x) |neighbor|
blocks.getBlock(neighbor.blocks[z][y][0]).?.negative_x
else
.empty,
.negative_x => if (x > 0)
blocks.getBlock(self.blocks[z][y][x - 1]).?.positive_x
else if (neighbors.negative_x) |neighbor|
blocks.getBlock(neighbor.blocks[z][y][chunk_size - 1]).?.positive_x
else
.empty,
.positive_y => if (y + 1 < chunk_size)
blocks.getBlock(self.blocks[z][y + 1][x]).?.negative_y
else if (neighbors.positive_y) |neighbor|
blocks.getBlock(neighbor.blocks[z][0][x]).?.negative_y
else
.empty,
.negative_y => if (y > 0)
blocks.getBlock(self.blocks[z][y - 1][x]).?.positive_y
else if (neighbors.negative_y) |neighbor|
blocks.getBlock(neighbor.blocks[z][chunk_size - 1][x]).?.positive_y
else
.empty,
.positive_z => if (z + 1 < chunk_size)
blocks.getBlock(self.blocks[z + 1][y][x]).?.negative_z
else if (neighbors.positive_z) |neighbor|
blocks.getBlock(neighbor.blocks[0][y][x]).?.negative_z
else
.empty,
.negative_z => if (z > 0)
blocks.getBlock(self.blocks[z - 1][y][x]).?.positive_z
else if (neighbors.negative_z) |neighbor|
blocks.getBlock(neighbor.blocks[chunk_size - 1][y][x]).?.positive_z
else
.empty,
};
}