Test how well a sparse 3d texture would work for storing and interpolating light data.

This commit is contained in:
IntegratedQuantum 2023-11-20 13:03:28 +01:00
parent 0adfbbc79e
commit 0008d7f1fa
7 changed files with 353 additions and 32 deletions

View File

@ -2,6 +2,7 @@
in vec3 mvVertexPos; in vec3 mvVertexPos;
in vec3 light; in vec3 light;
in vec3 chunkPos;
flat in int blockType; flat in int blockType;
flat in int faceNormal; flat in int faceNormal;
flat in int modelIndex; flat in int modelIndex;
@ -15,6 +16,9 @@ in vec3 direction;
uniform sampler2DArray texture_sampler; uniform sampler2DArray texture_sampler;
uniform sampler2DArray emissionSampler; uniform sampler2DArray emissionSampler;
uniform uint chunkDataIndex;
uniform vec3 ambientLight;
uniform int voxelSize;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
@ -31,6 +35,69 @@ layout(std430, binding = 1) buffer _textureData
TextureData textureData[]; TextureData textureData[];
}; };
struct ChunkData {
uint lightMapPtrs[6*6*6];
};
struct LightData {
int values[8*8*8];
};
layout(std430, binding = 7) buffer _chunkData
{
ChunkData chunkData[];
};
layout(std430, binding = 8) buffer _lightData
{
LightData lightData[];
};
vec3 sampleLight(ivec3 pos) {
pos += 8;
ivec3 rough = pos/8;
int roughIndex = (rough.x*6 + rough.y)*6 + rough.z;
ivec3 fine = pos&7;
int fineIndex = (fine.x*8 + fine.y)*8 + fine.z;
int lightValue = lightData[chunkData[chunkDataIndex].lightMapPtrs[roughIndex]].values[fineIndex];
vec3 sunLight = vec3(
lightValue >> 25 & 31,
lightValue >> 20 & 31,
lightValue >> 15 & 31
);
vec3 blockLight = vec3(
lightValue >> 10 & 31,
lightValue >> 5 & 31,
lightValue >> 0 & 31
);
return max(sunLight*ambientLight, blockLight)/32;
}
vec3 sCurve(vec3 x) {
return (3*x - 2*x*x)*x;
}
vec3 getLight(vec3 pos, vec3 normal) {
pos += normal/2;
pos -= vec3(0.5, 0.5, 0.5);
ivec3 start = ivec3(floor(pos));
vec3 diff = sCurve(pos - start);
vec3 invDiff = 1 - diff;
vec3 state = vec3(0);
for(int dx = 0; dx < 2; dx++) {
for(int dy = 0; dy < 2; dy++) {
for(int dz = 0; dz < 2; dz++) {
ivec3 delta = ivec3(dx, dy, dz);
vec3 light = sampleLight(start + delta);
bvec3 isOne = bvec3(notEqual(delta, ivec3(0)));
vec3 interpolation = mix(invDiff, diff, isOne);
state += light*interpolation.x*interpolation.y*interpolation.z;
}
}
}
return state;
}
const float[6] normalVariations = float[6]( const float[6] normalVariations = float[6](
1.0, //vec3(0, 1, 0), 1.0, //vec3(0, 1, 0),
@ -40,6 +107,14 @@ const float[6] normalVariations = float[6](
0.96, //vec3(0, 0, 1), 0.96, //vec3(0, 0, 1),
0.88 //vec3(0, 0, -1) 0.88 //vec3(0, 0, -1)
); );
const vec3[6] normals = vec3[6](
vec3(0, 1, 0),
vec3(0, -1, 0),
vec3(1, 0, 0),
vec3(-1, 0, 0),
vec3(0, 0, 1),
vec3(0, 0, -1)
);
float ditherThresholds[16] = float[16] ( float ditherThresholds[16] = float[16] (
1/17.0, 9/17.0, 3/17.0, 11/17.0, 1/17.0, 9/17.0, 3/17.0, 11/17.0,
@ -82,6 +157,7 @@ void main() {
uint textureIndex = textureData[blockType].textureIndices[faceNormal]; uint textureIndex = textureData[blockType].textureIndices[faceNormal];
float normalVariation = normalVariations[faceNormal]; float normalVariation = normalVariations[faceNormal];
vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex); vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex);
vec3 light = getLight(chunkPos + startPosition/16.0/voxelSize, normals[faceNormal]);
fragColor = texture(texture_sampler, textureCoords)*vec4(light*normalVariation, 1); fragColor = texture(texture_sampler, textureCoords)*vec4(light*normalVariation, 1);
if(!passDitherTest(fragColor.a)) discard; if(!passDitherTest(fragColor.a)) discard;

View File

@ -2,6 +2,7 @@
out vec3 mvVertexPos; out vec3 mvVertexPos;
out vec3 light; out vec3 light;
out vec3 chunkPos;
flat out int blockType; flat out int blockType;
flat out int modelIndex; flat out int modelIndex;
flat out int faceNormal; flat out int faceNormal;
@ -22,7 +23,6 @@ uniform vec3 modelPosition;
struct FaceData { struct FaceData {
int encodedPositionAndNormalsAndPermutation; int encodedPositionAndNormalsAndPermutation;
int blockAndModel; int blockAndModel;
int light[4];
}; };
layout(std430, binding = 3) buffer _faceData layout(std430, binding = 3) buffer _faceData
{ {
@ -131,18 +131,7 @@ void main() {
int vertexID = gl_VertexID%4; int vertexID = gl_VertexID%4;
int encodedPositionAndNormalsAndPermutation = faceData[faceID].encodedPositionAndNormalsAndPermutation; int encodedPositionAndNormalsAndPermutation = faceData[faceID].encodedPositionAndNormalsAndPermutation;
int blockAndModel = faceData[faceID].blockAndModel; int blockAndModel = faceData[faceID].blockAndModel;
int fullLight = faceData[faceID].light[vertexID]; light = vec3(1, 1, 1);
vec3 sunLight = vec3(
fullLight >> 25 & 31,
fullLight >> 20 & 31,
fullLight >> 15 & 31
);
vec3 blockLight = vec3(
fullLight >> 10 & 31,
fullLight >> 5 & 31,
fullLight >> 0 & 31
);
light = max(sunLight*ambientLight, blockLight)/32;
isBackFace = encodedPositionAndNormalsAndPermutation>>19 & 1; isBackFace = encodedPositionAndNormalsAndPermutation>>19 & 1;
int oldNormal = (encodedPositionAndNormalsAndPermutation >> 20) & 7; int oldNormal = (encodedPositionAndNormalsAndPermutation >> 20) & 7;
mat3 permutationMatrix = permutationMatrices[(encodedPositionAndNormalsAndPermutation >> 23) & 7]; mat3 permutationMatrix = permutationMatrices[(encodedPositionAndNormalsAndPermutation >> 23) & 7];
@ -158,6 +147,7 @@ void main() {
encodedPositionAndNormalsAndPermutation >> 5 & 31, encodedPositionAndNormalsAndPermutation >> 5 & 31,
encodedPositionAndNormalsAndPermutation >> 10 & 31 encodedPositionAndNormalsAndPermutation >> 10 & 31
); );
chunkPos = vec3(position) - normals[normal];
int octantIndex = (position.x >> 4) | (position.y >> 4)<<1 | (position.z >> 4)<<2; int octantIndex = (position.x >> 4) | (position.y >> 4)<<1 | (position.z >> 4)<<2;
if((visibilityMask & 1<<octantIndex) == 0) { // discard face if((visibilityMask & 1<<octantIndex) == 0) { // discard face
gl_Position = vec4(-2, -2, -2, 1); gl_Position = vec4(-2, -2, -2, 1);

View File

@ -2,6 +2,7 @@
in vec3 mvVertexPos; in vec3 mvVertexPos;
in vec3 light; in vec3 light;
in vec3 chunkPos;
flat in int blockType; flat in int blockType;
flat in int faceNormal; flat in int faceNormal;
flat in int modelIndex; flat in int modelIndex;
@ -16,6 +17,9 @@ uniform sampler2DArray texture_sampler;
uniform sampler2DArray emissionSampler; uniform sampler2DArray emissionSampler;
uniform samplerCube reflectionMap; uniform samplerCube reflectionMap;
uniform float reflectionMapSize; uniform float reflectionMapSize;
uniform uint chunkDataIndex;
uniform vec3 ambientLight;
uniform int voxelSize;
layout(binding = 3) uniform sampler2D depthTexture; layout(binding = 3) uniform sampler2D depthTexture;
@ -40,6 +44,69 @@ layout(std430, binding = 1) buffer _textureData
TextureData textureData[]; TextureData textureData[];
}; };
struct ChunkData {
uint lightMapPtrs[6*6*6];
};
struct LightData {
int values[8*8*8];
};
layout(std430, binding = 7) buffer _chunkData
{
ChunkData chunkData[];
};
layout(std430, binding = 8) buffer _lightData
{
LightData lightData[];
};
vec3 sampleLight(ivec3 pos) {
pos += 8;
ivec3 rough = pos/8;
int roughIndex = (rough.x*6 + rough.y)*6 + rough.z;
ivec3 fine = pos&7;
int fineIndex = (fine.x*8 + fine.y)*8 + fine.z;
int lightValue = lightData[chunkData[chunkDataIndex].lightMapPtrs[roughIndex]].values[fineIndex];
vec3 sunLight = vec3(
lightValue >> 25 & 31,
lightValue >> 20 & 31,
lightValue >> 15 & 31
);
vec3 blockLight = vec3(
lightValue >> 10 & 31,
lightValue >> 5 & 31,
lightValue >> 0 & 31
);
return max(sunLight*ambientLight, blockLight)/32;
}
vec3 sCurve(vec3 x) {
return (3*x - 2*x*x)*x;
}
vec3 getLight(vec3 pos, vec3 normal) {
pos += normal/2;
pos -= vec3(0.5, 0.5, 0.5);
ivec3 start = ivec3(floor(pos));
vec3 diff = sCurve(pos - start);
vec3 invDiff = 1 - diff;
vec3 state = vec3(0);
for(int dx = 0; dx < 2; dx++) {
for(int dy = 0; dy < 2; dy++) {
for(int dz = 0; dz < 2; dz++) {
ivec3 delta = ivec3(dx, dy, dz);
vec3 light = sampleLight(start + delta);
bvec3 isOne = bvec3(notEqual(delta, ivec3(0)));
vec3 interpolation = mix(invDiff, diff, isOne);
state += light*interpolation.x*interpolation.y*interpolation.z;
}
}
}
return state;
}
const float[6] normalVariations = float[6]( const float[6] normalVariations = float[6](
1.0, //vec3(0, 1, 0), 1.0, //vec3(0, 1, 0),
@ -142,6 +209,7 @@ void main() {
float fogDistance = calculateFogDistance(dist, textureData[blockType].fogDensity*densityAdjustment); float fogDistance = calculateFogDistance(dist, textureData[blockType].fogDensity*densityAdjustment);
float airFogDistance = calculateFogDistance(dist, fog.density*densityAdjustment); float airFogDistance = calculateFogDistance(dist, fog.density*densityAdjustment);
vec3 fogColor = unpackColor(textureData[blockType].fogColor); vec3 fogColor = unpackColor(textureData[blockType].fogColor);
vec3 light = getLight(chunkPos + startPosition/16.0/voxelSize, normals[faceNormal]);
vec4 textureColor = texture(texture_sampler, textureCoords)*vec4(light*normalVariation, 1); vec4 textureColor = texture(texture_sampler, textureCoords)*vec4(light*normalVariation, 1);
if(isBackFace == 0) { if(isBackFace == 0) {
textureColor.rgb *= textureColor.a; textureColor.rgb *= textureColor.a;

View File

@ -1,6 +1,7 @@
#version 450 #version 450
in vec3 mvVertexPos; in vec3 mvVertexPos;
in vec3 chunkPos;
in vec3 light; // TODO: This doesn't work here. in vec3 light; // TODO: This doesn't work here.
flat in int blockType; flat in int blockType;
flat in int faceNormal; flat in int faceNormal;
@ -15,6 +16,8 @@ in vec3 direction;
uniform sampler2DArray texture_sampler; uniform sampler2DArray texture_sampler;
uniform sampler2DArray emissionSampler; uniform sampler2DArray emissionSampler;
uniform uint chunkDataIndex;
uniform vec3 ambientLight;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
@ -43,6 +46,69 @@ layout(std430, binding = 4) buffer _voxelModels
VoxelModel voxelModels[]; VoxelModel voxelModels[];
}; };
struct ChunkData {
uint lightMapPtrs[6*6*6];
};
struct LightData {
int values[8*8*8];
};
layout(std430, binding = 7) buffer _chunkData
{
ChunkData chunkData[];
};
layout(std430, binding = 8) buffer _lightData
{
LightData lightData[];
};
vec3 sampleLight(ivec3 pos) {
pos += 8;
ivec3 rough = pos/8;
int roughIndex = (rough.x*6 + rough.y)*6 + rough.z;
ivec3 fine = pos&7;
int fineIndex = (fine.x*8 + fine.y)*8 + fine.z;
int lightValue = lightData[chunkData[chunkDataIndex].lightMapPtrs[roughIndex]].values[fineIndex];
vec3 sunLight = vec3(
lightValue >> 25 & 31,
lightValue >> 20 & 31,
lightValue >> 15 & 31
);
vec3 blockLight = vec3(
lightValue >> 10 & 31,
lightValue >> 5 & 31,
lightValue >> 0 & 31
);
return max(sunLight*ambientLight, blockLight)/32;
}
vec3 sCurve(vec3 x) {
return (3*x - 2*x*x)*x;
}
vec3 getLight(vec3 pos, vec3 normal) {
pos += normal/2;
pos -= vec3(0.5, 0.5, 0.5);
ivec3 start = ivec3(floor(pos));
vec3 diff = sCurve(pos - start);
vec3 invDiff = 1 - diff;
vec3 state = vec3(0);
for(int dx = 0; dx < 2; dx++) {
for(int dy = 0; dy < 2; dy++) {
for(int dz = 0; dz < 2; dz++) {
ivec3 delta = ivec3(dx, dy, dz);
vec3 light = sampleLight(start + delta);
bvec3 isOne = bvec3(notEqual(delta, ivec3(0)));
vec3 interpolation = mix(invDiff, diff, isOne);
state += light*interpolation.x*interpolation.y*interpolation.z;
}
}
}
return state;
}
const float[6] normalVariations = float[6]( const float[6] normalVariations = float[6](
1.0, //vec3(0, 1, 0), 1.0, //vec3(0, 1, 0),
@ -229,6 +295,8 @@ void main() {
float normalVariation = normalVariations[result.normal]; float normalVariation = normalVariations[result.normal];
float lod = getLod(result.voxelPosition, result.normal, direction, variance); float lod = getLod(result.voxelPosition, result.normal, direction, variance);
ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir); ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir);
vec3 pos = chunkPos + vec3(result.voxelPosition)/16.0 + 1.0/32.0;
vec3 light = getLight(pos, normals[result.normal]);
fragColor = mipMapSample(texture_sampler, textureCoords, textureIndex, lod)*vec4(light*normalVariation, 1); fragColor = mipMapSample(texture_sampler, textureCoords, textureIndex, lod)*vec4(light*normalVariation, 1);
if(!passDitherTest(fragColor.a)) discard; if(!passDitherTest(fragColor.a)) discard;

View File

@ -411,6 +411,7 @@ pub const meshing = struct {
voxelSize: c_int, voxelSize: c_int,
zNear: c_int, zNear: c_int,
zFar: c_int, zFar: c_int,
chunkDataIndex: c_int,
}; };
pub var uniforms: UniformStruct = undefined; pub var uniforms: UniformStruct = undefined;
pub var voxelUniforms: UniformStruct = undefined; pub var voxelUniforms: UniformStruct = undefined;
@ -419,6 +420,8 @@ pub const meshing = struct {
var vbo: c_uint = undefined; var vbo: c_uint = undefined;
var faces: std.ArrayList(u32) = undefined; var faces: std.ArrayList(u32) = undefined;
pub var faceBuffer: graphics.LargeBuffer(FaceData) = undefined; pub var faceBuffer: graphics.LargeBuffer(FaceData) = undefined;
pub var chunkBuffer: graphics.LargeBuffer(ChunkData) = undefined;
pub var lightBuffer: graphics.LargeBuffer(LightData) = undefined;
pub var quadsDrawn: usize = 0; pub var quadsDrawn: usize = 0;
pub var transparentQuadsDrawn: usize = 0; pub var transparentQuadsDrawn: usize = 0;
@ -442,6 +445,11 @@ pub const meshing = struct {
faces = try std.ArrayList(u32).initCapacity(main.globalAllocator, 65536); faces = try std.ArrayList(u32).initCapacity(main.globalAllocator, 65536);
try faceBuffer.init(main.globalAllocator, 1 << 20, 3); try faceBuffer.init(main.globalAllocator, 1 << 20, 3);
try chunkBuffer.init(main.globalAllocator, 1 << 10, 7);
try lightBuffer.init(main.globalAllocator, 1 << 10, 8);
var allocation: graphics.SubAllocation = .{.start = undefined, .len = 0};
try lightBuffer.uploadData(&.{.{.values = .{0}**(8*8*8)}}, &allocation);
std.debug.assert(allocation.start == 0); // Reserve 0 for null
} }
pub fn deinit() void { pub fn deinit() void {
@ -451,14 +459,20 @@ pub const meshing = struct {
c.glDeleteBuffers(1, &vbo); c.glDeleteBuffers(1, &vbo);
faces.deinit(); faces.deinit();
faceBuffer.deinit(); faceBuffer.deinit();
chunkBuffer.deinit();
lightBuffer.deinit();
} }
pub fn beginRender() !void { pub fn beginRender() !void {
try faceBuffer.beginRender(); try faceBuffer.beginRender();
try chunkBuffer.beginRender();
try lightBuffer.beginRender();
} }
pub fn endRender() void { pub fn endRender() void {
faceBuffer.endRender(); faceBuffer.endRender();
chunkBuffer.endRender();
lightBuffer.endRender();
} }
fn bindCommonUniforms(locations: *UniformStruct, projMatrix: Mat4f, ambient: Vec3f) void { fn bindCommonUniforms(locations: *UniformStruct, projMatrix: Mat4f, ambient: Vec3f) void {
@ -519,7 +533,15 @@ pub const meshing = struct {
typ: u16, typ: u16,
modelIndex: u16, modelIndex: u16,
}, },
light: [4]u32 = .{0, 0, 0, 0}, //light: [4]u32 = .{0, 0, 0, 0},
};
pub const ChunkData = extern struct {
lightMapPtrs: [6*6*6]u32,
};
pub const LightData = extern struct {
values: [8*8*8]u32,
}; };
const PrimitiveMesh = struct { const PrimitiveMesh = struct {
@ -577,7 +599,20 @@ pub const meshing = struct {
i += neighborFaces.items.len; i += neighborFaces.items.len;
} }
for(self.completeList) |*face| { for(self.completeList) |*face| {
face.light = getLight(parent, face.position.x, face.position.y, face.position.z, face.position.normal); if(face.blockAndModel.modelIndex != 0 or true) { // Non-cube model: Add all light data.
for(&[_]i32{-1, 1}) |dx| {
for(&[_]i32{-1, 1}) |dy| {
for(&[_]i32{-1, 1}) |dz| {
const x = @divFloor((face.position.x -% Neighbors.relX[face.position.normal] +% dx) +% 8, 8);
const y = @divFloor((face.position.y -% Neighbors.relY[face.position.normal] +% dy) +% 8, 8);
const z = @divFloor((face.position.z -% Neighbors.relZ[face.position.normal] +% dz) +% 8, 8);
parent.needsLightData[@intCast((x*6 + y)*6 + z)] = true;
}
}
}
} else { // TODO: Simpler/Faster approach for cube models.
}
} }
try self.uploadData(); try self.uploadData();
} }
@ -754,6 +789,9 @@ pub const meshing = struct {
lastTransparentUpdatePos: Vec3i = Vec3i{0, 0, 0}, lastTransparentUpdatePos: Vec3i = Vec3i{0, 0, 0},
refCount: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(1), refCount: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(1),
needsNeighborUpdate: bool = false, needsNeighborUpdate: bool = false,
chunkData: ChunkData,
chunkDataAllocation: graphics.SubAllocation = .{.start = 0, .len = 0},
needsLightData: [6*6*6]bool = undefined,
chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6, chunkBorders: [6]BoundingRectToNeighborChunk = [1]BoundingRectToNeighborChunk{.{}} ** 6,
@ -770,10 +808,21 @@ pub const meshing = struct {
.transparentMesh = .{}, .transparentMesh = .{},
.chunk = chunk, .chunk = chunk,
.lightingData = lightingData, .lightingData = lightingData,
.chunkData = .{.lightMapPtrs = .{0}**(6*6*6)},
}; };
} }
pub fn deinit(self: *ChunkMesh) void { pub fn deinit(self: *ChunkMesh) void {
chunkBuffer.free(self.chunkDataAllocation) catch |err| {
std.log.err("Error while freeing mesh data: {s}", .{@errorName(err)});
};
for(self.chunkData.lightMapPtrs) |ptr| {
if(ptr != 0) {
lightBuffer.free(.{.start = @intCast(ptr), .len = 1}) catch |err| {
std.log.err("Error while freeing mesh data: {s}", .{@errorName(err)});
};
}
}
std.debug.assert(self.refCount.load(.Monotonic) == 0); std.debug.assert(self.refCount.load(.Monotonic) == 0);
self.opaqueMesh.deinit(); self.opaqueMesh.deinit();
self.voxelMesh.deinit(); self.voxelMesh.deinit();
@ -991,15 +1040,11 @@ pub const meshing = struct {
} }
} }
if(neighborMesh != self) { if(neighborMesh != self) {
try neighborMesh.opaqueMesh.finish(neighborMesh); try neighborMesh.finish();
try neighborMesh.voxelMesh.finish(neighborMesh);
try neighborMesh.transparentMesh.finish(neighborMesh);
} }
} }
self.chunk.blocks[getIndex(x, y, z)] = newBlock; self.chunk.blocks[getIndex(x, y, z)] = newBlock;
try self.opaqueMesh.finish(self); try self.finish();
try self.voxelMesh.finish(self);
try self.transparentMesh.finish(self);
} }
pub inline fn constructFaceData(block: Block, normal: u3, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData { pub inline fn constructFaceData(block: Block, normal: u3, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData {
@ -1010,6 +1055,77 @@ pub const meshing = struct {
}; };
} }
fn getValues(mesh: *ChunkMesh, wx: i32, wy: i32, wz: i32) [6]u8 {
const x = (wx >> mesh.chunk.voxelSizeShift) & chunkMask;
const y = (wy >> mesh.chunk.voxelSizeShift) & chunkMask;
const z = (wz >> mesh.chunk.voxelSizeShift) & chunkMask;
const index = getIndex(x, y, z);
return .{
mesh.lightingData.*[0].data[index],
mesh.lightingData.*[1].data[index],
mesh.lightingData.*[2].data[index],
mesh.lightingData.*[3].data[index],
mesh.lightingData.*[4].data[index],
mesh.lightingData.*[5].data[index],
};
}
fn getLightAt(self: *ChunkMesh, x: i32, y: i32, z: i32) [6]u8 {
const wx = self.pos.wx +% x*self.pos.voxelSize;
const wy = self.pos.wy +% y*self.pos.voxelSize;
const wz = self.pos.wz +% z*self.pos.voxelSize;
if(x == x & chunkMask and y == y & chunkMask and z == z & chunkMask) {
return self.getValues(wx, wy, wz);
}
const neighborMesh = renderer.RenderStructure.getMeshFromAnyLodFromRenderThread(wx, wy, wz, self.pos.voxelSize) orelse return .{0, 0, 0, 0, 0, 0};
// TODO: If the neighbor mesh has a higher lod the transition isn't seamless.
return neighborMesh.getValues(wx, wy, wz);
}
fn getCompressedLightAt(self: *ChunkMesh, x: i32, y: i32, z: i32) u32 {
const light = self.getLightAt(x, y, z);
return (
@as(u32, light[0]) << 25 |
@as(u32, light[1]) << 20 |
@as(u32, light[2]) << 15 |
@as(u32, light[3]) << 10 |
@as(u32, light[4]) << 5 |
@as(u32, light[5]) << 0
);
}
fn finish(self: *ChunkMesh) !void {
@memset(&self.needsLightData, false);
try self.opaqueMesh.finish(self);
try self.voxelMesh.finish(self);
try self.transparentMesh.finish(self);
for(0..6) |x| {
for(0..6) |y| {
for(0..6) |z| {
const index = (x*6 + y)*6 + z;
if(!self.needsLightData[index]) continue;
var map: LightData = undefined;
for(0..8) |dx| {
for(0..8) |dy| {
for(0..8) |dz| {
map.values[(dx*8 + dy)*8 + dz] = self.getCompressedLightAt(@as(i32, @intCast(x*8 + dx)) - 8, @as(i32, @intCast(y*8 + dy)) - 8, @as(i32, @intCast(z*8 + dz)) - 8);
}
}
}
var allocation: graphics.SubAllocation = .{.start = undefined, .len = 0};
if(self.chunkData.lightMapPtrs[index] != 0) {
allocation.start = @intCast(self.chunkData.lightMapPtrs[index]);
allocation.len = 1;
}
try lightBuffer.uploadData(&.{map}, &allocation);
self.chunkData.lightMapPtrs[index] = allocation.start;
}
}
}
try chunkBuffer.uploadData(&.{self.chunkData}, &self.chunkDataAllocation);
}
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void { pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
for(Neighbors.iterable) |neighbor| { for(Neighbors.iterable) |neighbor| {
const nullNeighborMesh = renderer.RenderStructure.getNeighborFromRenderThread(self.pos, self.pos.voxelSize, neighbor); const nullNeighborMesh = renderer.RenderStructure.getNeighborFromRenderThread(self.pos, self.pos.voxelSize, neighbor);
@ -1080,9 +1196,7 @@ pub const meshing = struct {
} }
} }
} }
try neighborMesh.opaqueMesh.finish(neighborMesh); try neighborMesh.finish();
try neighborMesh.voxelMesh.finish(neighborMesh);
try neighborMesh.transparentMesh.finish(neighborMesh);
continue; continue;
} }
// lod border: // lod border:
@ -1149,9 +1263,7 @@ pub const meshing = struct {
} }
} }
} }
try self.opaqueMesh.finish(self); try self.finish();
try self.voxelMesh.finish(self);
try self.transparentMesh.finish(self);
} }
pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void { pub fn render(self: *ChunkMesh, playerPosition: Vec3d) void {
@ -1164,6 +1276,7 @@ pub const meshing = struct {
); );
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask); c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
c.glUniform1i(uniforms.voxelSize, self.pos.voxelSize); c.glUniform1i(uniforms.voxelSize, self.pos.voxelSize);
c.glUniform1ui(uniforms.chunkDataIndex, self.chunkDataAllocation.start);
quadsDrawn += self.opaqueMesh.vertexCount/6; quadsDrawn += self.opaqueMesh.vertexCount/6;
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.opaqueMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.opaqueMesh.bufferAllocation.start*4); c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.opaqueMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.opaqueMesh.bufferAllocation.start*4);
} }
@ -1178,6 +1291,7 @@ pub const meshing = struct {
); );
c.glUniform1i(voxelUniforms.visibilityMask, self.visibilityMask); c.glUniform1i(voxelUniforms.visibilityMask, self.visibilityMask);
c.glUniform1i(voxelUniforms.voxelSize, self.pos.voxelSize); c.glUniform1i(voxelUniforms.voxelSize, self.pos.voxelSize);
c.glUniform1ui(voxelUniforms.chunkDataIndex, self.chunkDataAllocation.start);
quadsDrawn += self.voxelMesh.vertexCount/6; quadsDrawn += self.voxelMesh.vertexCount/6;
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.voxelMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.voxelMesh.bufferAllocation.start*4); c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.voxelMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.voxelMesh.bufferAllocation.start*4);
} }
@ -1279,6 +1393,7 @@ pub const meshing = struct {
); );
c.glUniform1i(transparentUniforms.visibilityMask, self.visibilityMask); c.glUniform1i(transparentUniforms.visibilityMask, self.visibilityMask);
c.glUniform1i(transparentUniforms.voxelSize, self.pos.voxelSize); c.glUniform1i(transparentUniforms.voxelSize, self.pos.voxelSize);
c.glUniform1ui(transparentUniforms.chunkDataIndex, self.chunkDataAllocation.start);
transparentQuadsDrawn += self.culledSortingCount; transparentQuadsDrawn += self.culledSortingCount;
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.culledSortingCount*6, c.GL_UNSIGNED_INT, null, self.transparentMesh.bufferAllocation.start*4); c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.culledSortingCount*6, c.GL_UNSIGNED_INT, null, self.transparentMesh.bufferAllocation.start*4);
} }

View File

@ -1332,7 +1332,7 @@ pub fn LargeBuffer(comptime Entry: type) type {
try self.fencedFreeLists[self.activeFence].append(allocation); try self.fencedFreeLists[self.activeFence].append(allocation);
} }
pub fn uploadData(self: *Self, data: []Entry, allocation: *SubAllocation) !void { pub fn uploadData(self: *Self, data: []const Entry, allocation: *SubAllocation) !void {
try self.free(allocation.*); try self.free(allocation.*);
if(data.len == 0) { if(data.len == 0) {
allocation.len = 0; allocation.len = 0;
@ -1854,9 +1854,7 @@ pub fn generateBlockTexture(blockType: u16) !Texture {
faceData[faces + 1] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1+1, 1, false); faceData[faces + 1] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirUp, 1, 1+1, 1, false);
faceData[faces + 2] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosZ, 1, 1, 1+1, false); faceData[faces + 2] = main.chunk.meshing.ChunkMesh.constructFaceData(block, main.chunk.Neighbors.dirPosZ, 1, 1, 1+1, false);
faces += 3; faces += 3;
for(faceData[0..faces]) |*face| { // TODO: Lighting
@memset(&face.light, ~@as(u32, 0));
}
var allocation: SubAllocation = .{.start = 0, .len = 0}; var allocation: SubAllocation = .{.start = 0, .len = 0};
try main.chunk.meshing.faceBuffer.uploadData(faceData[0..faces], &allocation); try main.chunk.meshing.faceBuffer.uploadData(faceData[0..faces], &allocation);

View File

@ -41,7 +41,13 @@ fn flawedRender() !void {
try draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left); try draw.print("Queue size: {}", .{main.threadPool.queueSize()}, 0, y, 8, .left);
y += 8; y += 8;
const faceDataSize = @sizeOf(main.chunk.meshing.FaceData); const faceDataSize = @sizeOf(main.chunk.meshing.FaceData);
try draw.print("ChunkMesh memory: {} MiB / {} MiB (fragmentation: {})", .{main.chunk.meshing.faceBuffer.used*faceDataSize >> 20, main.chunk.meshing.faceBuffer.capacity*faceDataSize >> 20, main.chunk.meshing.faceBuffer.freeBlocks.items.len}, 0, y, 8, .left); try draw.print("Chunk Face memory: {} MiB / {} MiB (fragmentation: {})", .{main.chunk.meshing.faceBuffer.used*faceDataSize >> 20, main.chunk.meshing.faceBuffer.capacity*faceDataSize >> 20, main.chunk.meshing.faceBuffer.freeBlocks.items.len}, 0, y, 8, .left);
y += 8;
const chunkDataSize = @sizeOf(main.chunk.meshing.ChunkData);
try draw.print("Chunk memory: {} MiB / {} MiB (fragmentation: {})", .{main.chunk.meshing.chunkBuffer.used*chunkDataSize >> 20, main.chunk.meshing.chunkBuffer.capacity*chunkDataSize >> 20, main.chunk.meshing.chunkBuffer.freeBlocks.items.len}, 0, y, 8, .left);
y += 8;
const lightDataSize = @sizeOf(main.chunk.meshing.LightData);
try draw.print("Chunk light memory: {} MiB / {} MiB (fragmentation: {})", .{main.chunk.meshing.lightBuffer.used*lightDataSize >> 20, main.chunk.meshing.lightBuffer.capacity*lightDataSize >> 20, main.chunk.meshing.lightBuffer.freeBlocks.items.len}, 0, y, 8, .left);
y += 8; y += 8;
try draw.print("Biome: {s}", .{main.game.world.?.playerBiome.load(.Monotonic).id}, 0, y, 8, .left); try draw.print("Biome: {s}", .{main.game.world.?.playerBiome.load(.Monotonic).id}, 0, y, 8, .left);
y += 8; y += 8;