mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-04 03:37:59 -04:00
Don't load meshes until all surrounding (3×3×3) chunks finished light propagation.
This fixes a bunch of lighting bugs: Fixes #219 Fixes #170 Fixes #163
This commit is contained in:
parent
62d4920869
commit
08704ef4aa
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Atomic = std.atomic.Value;
|
||||||
|
|
||||||
const main = @import("root");
|
const main = @import("root");
|
||||||
const blocks = main.blocks;
|
const blocks = main.blocks;
|
||||||
@ -256,9 +257,8 @@ const PrimitiveMesh = struct {
|
|||||||
if(x == x & chunk.chunkMask and y == y & chunk.chunkMask and z == z & chunk.chunkMask) {
|
if(x == x & chunk.chunkMask and y == y & chunk.chunkMask and z == z & chunk.chunkMask) {
|
||||||
return getValues(parent, wx, wy, wz);
|
return getValues(parent, wx, wy, wz);
|
||||||
}
|
}
|
||||||
const neighborMesh = mesh_storage.getMeshFromAnyLodAndIncreaseRefCount(wx, wy, wz, parent.pos.voxelSize) orelse return .{0, 0, 0, 0, 0, 0};
|
const neighborMesh = mesh_storage.getMeshAndIncreaseRefCount(.{.wx = wx, .wy = wy, .wz = wz, .voxelSize = parent.pos.voxelSize}) orelse return .{0, 0, 0, 0, 0, 0};
|
||||||
defer neighborMesh.decreaseRefCount();
|
defer neighborMesh.decreaseRefCount();
|
||||||
// TODO: If the neighbor mesh has a higher lod the transition isn't seamless.
|
|
||||||
return getValues(neighborMesh, wx, wy, wz);
|
return getValues(neighborMesh, wx, wy, wz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,6 +438,8 @@ pub const ChunkMesh = struct {
|
|||||||
needsLightRefresh: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
|
needsLightRefresh: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
|
||||||
needsMeshUpdate: bool = false,
|
needsMeshUpdate: bool = false,
|
||||||
finishedMeshing: bool = false,
|
finishedMeshing: bool = false,
|
||||||
|
finishedLighting: bool = false,
|
||||||
|
litNeighbors: Atomic(u32) = Atomic(u32).init(0),
|
||||||
mutex: std.Thread.Mutex = .{},
|
mutex: std.Thread.Mutex = .{},
|
||||||
|
|
||||||
chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6,
|
chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6,
|
||||||
@ -609,7 +611,7 @@ pub const ChunkMesh = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn regenerateMainMesh(self: *ChunkMesh) !void {
|
pub fn generateLightingData(self: *ChunkMesh) !void {
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
self.opaqueMesh.reset();
|
self.opaqueMesh.reset();
|
||||||
self.transparentMesh.reset();
|
self.transparentMesh.reset();
|
||||||
@ -618,6 +620,41 @@ pub const ChunkMesh = struct {
|
|||||||
|
|
||||||
try self.initLight();
|
try self.initLight();
|
||||||
|
|
||||||
|
self.mutex.lock();
|
||||||
|
self.finishedLighting = true;
|
||||||
|
self.mutex.unlock();
|
||||||
|
|
||||||
|
// Only generate a mesh if the surrounding 27 chunks finished the light generation steps.
|
||||||
|
var dx: i32 = -1;
|
||||||
|
while(dx <= 1): (dx += 1) {
|
||||||
|
var dy: i32 = -1;
|
||||||
|
while(dy <= 1): (dy += 1) {
|
||||||
|
var dz: i32 = -1;
|
||||||
|
while(dz <= 1): (dz += 1) {
|
||||||
|
var pos = self.pos;
|
||||||
|
pos.wx +%= pos.voxelSize*chunk.chunkSize*dx;
|
||||||
|
pos.wy +%= pos.voxelSize*chunk.chunkSize*dy;
|
||||||
|
pos.wz +%= pos.voxelSize*chunk.chunkSize*dz;
|
||||||
|
const neighborMesh = mesh_storage.getMeshAndIncreaseRefCount(pos) orelse continue;
|
||||||
|
defer neighborMesh.decreaseRefCount();
|
||||||
|
|
||||||
|
const shiftSelf: u5 = @intCast(((dx + 1)*3 + dy + 1)*3 + dz + 1);
|
||||||
|
const shiftOther: u5 = @intCast(((-dx + 1)*3 + -dy + 1)*3 + -dz + 1);
|
||||||
|
if(neighborMesh.litNeighbors.fetchOr(@as(u27, 1) << shiftOther, .Monotonic) ^ @as(u27, 1) << shiftOther == ~@as(u27, 0)) { // Trigger mesh creation for neighbor
|
||||||
|
try neighborMesh.generateMesh();
|
||||||
|
}
|
||||||
|
neighborMesh.mutex.lock();
|
||||||
|
const neighborFinishedLighting = neighborMesh.finishedLighting;
|
||||||
|
neighborMesh.mutex.unlock();
|
||||||
|
if(neighborFinishedLighting and self.litNeighbors.fetchOr(@as(u27, 1) << shiftSelf, .Monotonic) ^ @as(u27, 1) << shiftSelf == ~@as(u27, 0)) {
|
||||||
|
try self.generateMesh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateMesh(self: *ChunkMesh) !void {
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
var n: u32 = 0;
|
var n: u32 = 0;
|
||||||
var x: u8 = 0;
|
var x: u8 = 0;
|
||||||
@ -985,6 +1022,7 @@ pub const ChunkMesh = struct {
|
|||||||
defer self.mutex.unlock();
|
defer self.mutex.unlock();
|
||||||
_ = self.needsLightRefresh.swap(false, .AcqRel);
|
_ = self.needsLightRefresh.swap(false, .AcqRel);
|
||||||
try self.finishData();
|
try self.finishData();
|
||||||
|
try mesh_storage.finishMesh(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
|
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
|
||||||
|
@ -978,6 +978,19 @@ pub fn addMeshToStorage(mesh: *chunk_meshing.ChunkMesh) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn finishMesh(mesh: *chunk_meshing.ChunkMesh) !void {
|
||||||
|
mutex.lock();
|
||||||
|
defer mutex.unlock();
|
||||||
|
mesh.increaseRefCount();
|
||||||
|
updatableList.append(mesh) catch |err| {
|
||||||
|
std.log.err("Error while regenerating mesh: {s}", .{@errorName(err)});
|
||||||
|
if(@errorReturnTrace()) |trace| {
|
||||||
|
std.log.err("Trace: {}", .{trace});
|
||||||
|
}
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const MeshGenerationTask = struct {
|
pub const MeshGenerationTask = struct {
|
||||||
mesh: *chunk.Chunk,
|
mesh: *chunk.Chunk,
|
||||||
|
|
||||||
@ -1008,14 +1021,14 @@ pub const MeshGenerationTask = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: *MeshGenerationTask) Allocator.Error!void {
|
pub fn run(self: *MeshGenerationTask) Allocator.Error!void {
|
||||||
|
defer main.globalAllocator.destroy(self);
|
||||||
const pos = self.mesh.pos;
|
const pos = self.mesh.pos;
|
||||||
const mesh = try main.globalAllocator.create(chunk_meshing.ChunkMesh);
|
const mesh = try main.globalAllocator.create(chunk_meshing.ChunkMesh);
|
||||||
try mesh.init(pos, self.mesh);
|
try mesh.init(pos, self.mesh);
|
||||||
mesh.regenerateMainMesh() catch |err| {
|
defer mesh.decreaseRefCount();
|
||||||
|
mesh.generateLightingData() catch |err| {
|
||||||
switch(err) {
|
switch(err) {
|
||||||
error.AlreadyStored => {
|
error.AlreadyStored => {
|
||||||
mesh.decreaseRefCount();
|
|
||||||
main.globalAllocator.destroy(self);
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
else => |_err| {
|
else => |_err| {
|
||||||
@ -1023,16 +1036,6 @@ pub const MeshGenerationTask = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mutex.lock();
|
|
||||||
defer mutex.unlock();
|
|
||||||
updatableList.append(mesh) catch |err| {
|
|
||||||
std.log.err("Error while regenerating mesh: {s}", .{@errorName(err)});
|
|
||||||
if(@errorReturnTrace()) |trace| {
|
|
||||||
std.log.err("Trace: {}", .{trace});
|
|
||||||
}
|
|
||||||
main.globalAllocator.destroy(self.mesh);
|
|
||||||
};
|
|
||||||
main.globalAllocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean(self: *MeshGenerationTask) void {
|
pub fn clean(self: *MeshGenerationTask) void {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user