mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Fix chunk meshes at lod borders.
This commit is contained in:
parent
219957681d
commit
26f4dd2ff2
@ -5,7 +5,7 @@ out vec2 outTexCoord;
|
|||||||
flat out float textureIndex;
|
flat out float textureIndex;
|
||||||
out float outNormalVariation;
|
out float outNormalVariation;
|
||||||
|
|
||||||
|
uniform int visibilityMask;
|
||||||
uniform mat4 projectionMatrix;
|
uniform mat4 projectionMatrix;
|
||||||
uniform mat4 viewMatrix;
|
uniform mat4 viewMatrix;
|
||||||
uniform vec3 modelPosition;
|
uniform vec3 modelPosition;
|
||||||
@ -46,13 +46,13 @@ const vec3[6] normals = vec3[6](
|
|||||||
vec3(0, 0, 1),
|
vec3(0, 0, 1),
|
||||||
vec3(0, 0, -1)
|
vec3(0, 0, -1)
|
||||||
);
|
);
|
||||||
const vec3[6] positionOffset = vec3[6](
|
const ivec3[6] positionOffset = ivec3[6](
|
||||||
vec3(0, 0, 0),
|
ivec3(0, 0, 0),
|
||||||
vec3(0, 1, 0),
|
ivec3(0, 1, 0),
|
||||||
vec3(0, 0, 0),
|
ivec3(0, 0, 0),
|
||||||
vec3(1, 0, 0),
|
ivec3(1, 0, 0),
|
||||||
vec3(0, 0, 0),
|
ivec3(0, 0, 0),
|
||||||
vec3(0, 0, 1)
|
ivec3(0, 0, 1)
|
||||||
);
|
);
|
||||||
const ivec3[6] textureX = ivec3[6](
|
const ivec3[6] textureX = ivec3[6](
|
||||||
ivec3(1, 0, 0),
|
ivec3(1, 0, 0),
|
||||||
@ -81,14 +81,20 @@ void main() {
|
|||||||
textureIndex = texCoordz + time / animationTimes[texCoordz] % animationFrames[texCoordz];
|
textureIndex = texCoordz + time / animationTimes[texCoordz] % animationFrames[texCoordz];
|
||||||
outTexCoord = vec2(float(vertexID>>1 & 1)*voxelSize, float(vertexID & 1)*voxelSize);
|
outTexCoord = vec2(float(vertexID>>1 & 1)*voxelSize, float(vertexID & 1)*voxelSize);
|
||||||
|
|
||||||
vec3 position = vec3(
|
ivec3 position = ivec3(
|
||||||
encodedPosition & 31,
|
encodedPosition & 31,
|
||||||
encodedPosition >> 5 & 31,
|
encodedPosition >> 5 & 31,
|
||||||
encodedPosition >> 10 & 31
|
encodedPosition >> 10 & 31
|
||||||
);
|
);
|
||||||
|
int octantIndex = (position.x >> 4) | (position.y >> 4)<<1 | (position.z >> 4)<<2;
|
||||||
|
if((visibilityMask & 1<<octantIndex) == 0) { // discard face
|
||||||
|
gl_Position = vec4(-2, -2, -2, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
position += positionOffset[normal];
|
position += positionOffset[normal];
|
||||||
position += vec3(equal(textureX[normal], ivec3(-1, -1, -1))) + (vertexID>>1 & 1)*textureX[normal];
|
position += ivec3(equal(textureX[normal], ivec3(-1, -1, -1))) + (vertexID>>1 & 1)*textureX[normal];
|
||||||
position += vec3(equal(textureY[normal], ivec3(-1, -1, -1))) + (vertexID & 1)*textureY[normal];
|
position += ivec3(equal(textureY[normal], ivec3(-1, -1, -1))) + (vertexID & 1)*textureY[normal];
|
||||||
|
|
||||||
vec3 globalPosition = position*voxelSize + modelPosition;
|
vec3 globalPosition = position*voxelSize + modelPosition;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ const Shader = graphics.Shader;
|
|||||||
const SSBO = graphics.SSBO;
|
const SSBO = graphics.SSBO;
|
||||||
const main = @import("main.zig");
|
const main = @import("main.zig");
|
||||||
const renderer = @import("renderer.zig");
|
const renderer = @import("renderer.zig");
|
||||||
|
const settings = @import("settings.zig");
|
||||||
const vec = @import("vec.zig");
|
const vec = @import("vec.zig");
|
||||||
const Vec3f = vec.Vec3f;
|
const Vec3f = vec.Vec3f;
|
||||||
const Vec3d = vec.Vec3d;
|
const Vec3d = vec.Vec3d;
|
||||||
@ -535,6 +536,7 @@ pub const meshing = struct {
|
|||||||
@"waterFog.color": c_int,
|
@"waterFog.color": c_int,
|
||||||
@"waterFog.density": c_int,
|
@"waterFog.density": c_int,
|
||||||
time: c_int,
|
time: c_int,
|
||||||
|
visibilityMask: c_int,
|
||||||
} = undefined;
|
} = undefined;
|
||||||
var vao: c_uint = undefined;
|
var vao: c_uint = undefined;
|
||||||
var vbo: c_uint = undefined;
|
var vbo: c_uint = undefined;
|
||||||
@ -600,6 +602,7 @@ pub const meshing = struct {
|
|||||||
vertexCount: u31 = 0,
|
vertexCount: u31 = 0,
|
||||||
generated: bool = false,
|
generated: bool = false,
|
||||||
mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
||||||
|
visibilityMask: u8 = 0xff,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, pos: ChunkPosition) ChunkMesh {
|
pub fn init(allocator: Allocator, pos: ChunkPosition) ChunkMesh {
|
||||||
return ChunkMesh{
|
return ChunkMesh{
|
||||||
@ -664,11 +667,10 @@ pub const meshing = struct {
|
|||||||
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
||||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||||
if(self.chunk == null) return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
|
if(self.chunk == null) return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
|
||||||
self.generated = true;
|
|
||||||
self.faces.shrinkRetainingCapacity(self.coreCount);
|
self.faces.shrinkRetainingCapacity(self.coreCount);
|
||||||
for(Neighbors.iterable) |neighbor| {
|
for(Neighbors.iterable) |neighbor| {
|
||||||
self.neighborStart[neighbor] = @intCast(u31, self.faces.items.len);
|
self.neighborStart[neighbor] = @intCast(u31, self.faces.items.len);
|
||||||
var nullNeighborMesh = renderer.RenderStructure.getNeighbor(self.pos, neighbor);
|
var nullNeighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor);
|
||||||
if(nullNeighborMesh) |neighborMesh| {
|
if(nullNeighborMesh) |neighborMesh| {
|
||||||
std.debug.assert(neighborMesh != self);
|
std.debug.assert(neighborMesh != self);
|
||||||
neighborMesh.mutex.lock();
|
neighborMesh.mutex.lock();
|
||||||
@ -726,16 +728,61 @@ pub const meshing = struct {
|
|||||||
}
|
}
|
||||||
neighborMesh.vertexCount = @intCast(u31, 6*(neighborMesh.faces.items.len-1)/2);
|
neighborMesh.vertexCount = @intCast(u31, 6*(neighborMesh.faces.items.len-1)/2);
|
||||||
neighborMesh.faceData.bufferData(u32, neighborMesh.faces.items);
|
neighborMesh.faceData.bufferData(u32, neighborMesh.faces.items);
|
||||||
} else {
|
continue;
|
||||||
// TODO: Resolution boundary.
|
}
|
||||||
|
}
|
||||||
|
// lod border:
|
||||||
|
if(self.pos.voxelSize == 1 << settings.highestLOD) continue;
|
||||||
|
var neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, 2*self.pos.voxelSize, neighbor) orelse return error.LODMissing;
|
||||||
|
neighborMesh.mutex.lock();
|
||||||
|
defer neighborMesh.mutex.unlock();
|
||||||
|
if(neighborMesh.generated) {
|
||||||
|
const x3: u8 = if(neighbor & 1 == 0) @intCast(u8, chunkMask) else 0;
|
||||||
|
const offsetX = @divExact(self.pos.wx, self.pos.voxelSize) & chunkSize;
|
||||||
|
const offsetY = @divExact(self.pos.wy, self.pos.voxelSize) & chunkSize;
|
||||||
|
const offsetZ = @divExact(self.pos.wz, self.pos.voxelSize) & chunkSize;
|
||||||
|
var x1: u8 = 0;
|
||||||
|
while(x1 < chunkSize): (x1 += 1) {
|
||||||
|
var x2: u8 = 0;
|
||||||
|
while(x2 < chunkSize): (x2 += 1) {
|
||||||
|
var x: u8 = undefined;
|
||||||
|
var y: u8 = undefined;
|
||||||
|
var z: u8 = undefined;
|
||||||
|
if(Neighbors.relX[neighbor] != 0) {
|
||||||
|
x = x3;
|
||||||
|
y = x1;
|
||||||
|
z = x2;
|
||||||
|
} else if(Neighbors.relY[neighbor] != 0) {
|
||||||
|
x = x1;
|
||||||
|
y = x3;
|
||||||
|
z = x2;
|
||||||
|
} else {
|
||||||
|
x = x2;
|
||||||
|
y = x1;
|
||||||
|
z = x3;
|
||||||
|
}
|
||||||
|
var otherX = @intCast(u8, (x+%Neighbors.relX[neighbor]+%offsetX >> 1) & chunkMask);
|
||||||
|
var otherY = @intCast(u8, (y+%Neighbors.relY[neighbor]+%offsetY >> 1) & chunkMask);
|
||||||
|
var otherZ = @intCast(u8, (z+%Neighbors.relZ[neighbor]+%offsetZ >> 1) & chunkMask);
|
||||||
|
var block = (&self.chunk.?.blocks)[getIndex(x, y, z)]; // ← a little hack that increases speed 100×. TODO: check if this is *that* compiler bug.
|
||||||
|
var otherBlock = (&neighborMesh.chunk.?.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a little hack that increases speed 100×. TODO: check if this is *that* compiler bug.
|
||||||
|
if(block.typ == 0 and otherBlock.typ != 0) { // TODO: Transparency
|
||||||
|
const normal: u32 = neighbor ^ 1;
|
||||||
|
const position: u32 = @as(u32, x) | @as(u32, y)<<5 | @as(u32, z)<<10;
|
||||||
|
const textureNormal = blocks.meshes.textureIndices(otherBlock)[neighbor] | normal<<24;
|
||||||
|
try self.faces.append(position);
|
||||||
|
try self.faces.append(textureNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Resolution boundary.
|
return error.LODMissing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.neighborStart[6] = @intCast(u31, self.faces.items.len);
|
self.neighborStart[6] = @intCast(u31, self.faces.items.len);
|
||||||
self.vertexCount = @intCast(u31, 6*(self.faces.items.len-1)/2);
|
self.vertexCount = @intCast(u31, 6*(self.faces.items.len-1)/2);
|
||||||
self.faceData.bufferData(u32, self.faces.items);
|
self.faceData.bufferData(u32, self.faces.items);
|
||||||
|
self.generated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
|
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
|
||||||
@ -749,6 +796,7 @@ pub const meshing = struct {
|
|||||||
@floatCast(f32, @intToFloat(f64, self.pos.wy) - playerPosition.y),
|
@floatCast(f32, @intToFloat(f64, self.pos.wy) - playerPosition.y),
|
||||||
@floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition.z)
|
@floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition.z)
|
||||||
);
|
);
|
||||||
|
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
|
||||||
self.faceData.bind(3);
|
self.faceData.bind(3);
|
||||||
c.glDrawElements(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null);
|
c.glDrawElements(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null);
|
||||||
}
|
}
|
||||||
|
@ -493,11 +493,12 @@ pub const RenderStructure = struct {
|
|||||||
return storageLists[lod][@intCast(usize, index)];
|
return storageLists[lod][@intCast(usize, index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNeighbor(_pos: chunk.ChunkPosition, neighbor: u3) ?*chunk.meshing.ChunkMesh {
|
pub fn getNeighbor(_pos: chunk.ChunkPosition, resolution: chunk.UChunkCoordinate, neighbor: u3) ?*chunk.meshing.ChunkMesh {
|
||||||
var pos = _pos;
|
var pos = _pos;
|
||||||
pos.wx += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relX[neighbor];
|
pos.wx += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relX[neighbor];
|
||||||
pos.wy += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relY[neighbor];
|
pos.wy += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relY[neighbor];
|
||||||
pos.wz += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relZ[neighbor];
|
pos.wz += pos.voxelSize*chunk.chunkSize*chunk.Neighbors.relZ[neighbor];
|
||||||
|
pos.voxelSize = resolution;
|
||||||
var node = _getNode(pos) orelse return null;
|
var node = _getNode(pos) orelse return null;
|
||||||
return &node.mesh;
|
return &node.mesh;
|
||||||
}
|
}
|
||||||
@ -518,6 +519,7 @@ pub const RenderStructure = struct {
|
|||||||
const lod = @intCast(u5, _lod);
|
const lod = @intCast(u5, _lod);
|
||||||
var maxRenderDistance = renderDistance*chunk.chunkSize << lod;
|
var maxRenderDistance = renderDistance*chunk.chunkSize << lod;
|
||||||
if(lod != 0) maxRenderDistance = @floatToInt(i32, @ceil(@intToFloat(f32, maxRenderDistance)*LODFactor));
|
if(lod != 0) maxRenderDistance = @floatToInt(i32, @ceil(@intToFloat(f32, maxRenderDistance)*LODFactor));
|
||||||
|
var sizeShift = chunk.chunkShift + lod;
|
||||||
const size = @intCast(chunk.UChunkCoordinate, chunk.chunkSize << lod);
|
const size = @intCast(chunk.UChunkCoordinate, chunk.chunkSize << lod);
|
||||||
const mask: chunk.ChunkCoordinate = size - 1;
|
const mask: chunk.ChunkCoordinate = size - 1;
|
||||||
const invMask: chunk.ChunkCoordinate = ~mask;
|
const invMask: chunk.ChunkCoordinate = ~mask;
|
||||||
@ -576,12 +578,13 @@ pub const RenderStructure = struct {
|
|||||||
.x = @intToFloat(f32, size),
|
.x = @intToFloat(f32, size),
|
||||||
.y = @intToFloat(f32, size),
|
.y = @intToFloat(f32, size),
|
||||||
.z = @intToFloat(f32, size),
|
.z = @intToFloat(f32, size),
|
||||||
}) and node.?.drawableChildren < 8) { // TODO: Case where more than 0 and less than 8 exist.
|
}) and node.?.mesh.visibilityMask != 0) {
|
||||||
try meshes.append(&node.?.mesh);
|
try meshes.append(&node.?.mesh);
|
||||||
}
|
}
|
||||||
if(lod+1 != storageLists.len and node.?.mesh.generated) {
|
if(lod+1 != storageLists.len and node.?.mesh.generated) {
|
||||||
if(_getNode(.{.wx=x, .wy=y, .wz=z, .voxelSize=@as(chunk.UChunkCoordinate, 1)<<(lod+1)})) |parent| {
|
if(_getNode(.{.wx=x, .wy=y, .wz=z, .voxelSize=@as(chunk.UChunkCoordinate, 1)<<(lod+1)})) |parent| {
|
||||||
parent.drawableChildren += 1;
|
const octantIndex = @intCast(u3, (x>>sizeShift & 1) | (y>>sizeShift & 1)<<1 | (z>>sizeShift & 1)<<2);
|
||||||
|
parent.mesh.visibilityMask &= ~(@as(u8, 1) << octantIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.?.drawableChildren = 0;
|
node.?.drawableChildren = 0;
|
||||||
@ -603,6 +606,22 @@ pub const RenderStructure = struct {
|
|||||||
for(oldList) |nullMesh| {
|
for(oldList) |nullMesh| {
|
||||||
if(nullMesh) |mesh| {
|
if(nullMesh) |mesh| {
|
||||||
if(mesh.shouldBeRemoved) {
|
if(mesh.shouldBeRemoved) {
|
||||||
|
if(mesh.mesh.pos.voxelSize != 1 << settings.highestLOD) {
|
||||||
|
if(_getNode(.{.wx=mesh.mesh.pos.wx, .wy=mesh.mesh.pos.wy, .wz=mesh.mesh.pos.wz, .voxelSize=2*mesh.mesh.pos.voxelSize})) |parent| {
|
||||||
|
const octantIndex = @intCast(u3, (mesh.mesh.pos.wx>>sizeShift & 1) | (mesh.mesh.pos.wy>>sizeShift & 1)<<1 | (mesh.mesh.pos.wz>>sizeShift & 1)<<2);
|
||||||
|
parent.mesh.visibilityMask |= @as(u8, 1) << octantIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the neighbors, so we don't get cracks when we look back:
|
||||||
|
for(chunk.Neighbors.iterable) |neighbor| {
|
||||||
|
if(getNeighbor(mesh.mesh.pos, mesh.mesh.pos.voxelSize, neighbor)) |neighborMesh| {
|
||||||
|
if(neighborMesh.generated) {
|
||||||
|
neighborMesh.mutex.lock();
|
||||||
|
defer neighborMesh.mutex.unlock();
|
||||||
|
try neighborMesh.uploadDataAndFinishNeighbors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(mesh.mesh.mutex.tryLock()) { // Make sure there is no task currently running on the thing.
|
if(mesh.mesh.mutex.tryLock()) { // Make sure there is no task currently running on the thing.
|
||||||
mesh.mesh.mutex.unlock();
|
mesh.mesh.mutex.unlock();
|
||||||
mesh.mesh.deinit();
|
mesh.mesh.deinit();
|
||||||
@ -641,14 +660,22 @@ pub const RenderStructure = struct {
|
|||||||
mutex.lock();
|
mutex.lock();
|
||||||
defer mutex.unlock();
|
defer mutex.unlock();
|
||||||
while(updatableList.items.len != 0) {
|
while(updatableList.items.len != 0) {
|
||||||
const pos = updatableList.pop();
|
const pos = updatableList.orderedRemove(0);
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
defer mutex.lock();
|
defer mutex.lock();
|
||||||
const nullNode = _getNode(pos);
|
const nullNode = _getNode(pos);
|
||||||
if(nullNode) |node| {
|
if(nullNode) |node| {
|
||||||
node.mesh.mutex.lock();
|
node.mesh.mutex.lock();
|
||||||
defer node.mesh.mutex.unlock();
|
defer node.mesh.mutex.unlock();
|
||||||
try node.mesh.uploadDataAndFinishNeighbors();
|
node.mesh.uploadDataAndFinishNeighbors() catch |err| {
|
||||||
|
if(err == error.LODMissing) {
|
||||||
|
mutex.lock();
|
||||||
|
defer mutex.unlock();
|
||||||
|
try updatableList.append(pos);
|
||||||
|
} else {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if(std.time.milliTimestamp() >= targetTime) break; // Update at least one mesh.
|
if(std.time.milliTimestamp() >= targetTime) break; // Update at least one mesh.
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user