The fog data is now part of the texture.

This is not really optimal, as this doesn't ensure that all textures of a block have the same fog, but this is an important step towards not storing the block id on the GPU and additionally this allows changing the fog of a block in future resource packs.
This commit is contained in:
IntegratedQuantum 2024-03-12 11:42:35 +01:00
parent a164ee6794
commit 80a4d2d35a
28 changed files with 121 additions and 52 deletions

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x010100,
"fogDensity" : 0.02,
"fogColor" : 0x0000ff,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/blue"
}

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x010000,
"fogDensity" : 0.02,
"fogColor" : 0x00ffff,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/cyan"
}

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x010001,
"fogDensity" : 0.02,
"fogColor" : 0x00ff00,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/green"
}

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x000100,
"fogDensity" : 0.02,
"fogColor" : 0xff00ff,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/magenta"
}

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x000101,
"fogDensity" : 0.02,
"fogColor" : 0xff0000,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/red"
}

View File

@ -6,10 +6,9 @@
],
"degradable" : true,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x000001,
"fogDensity" : 0.02,
"fogColor" : 0xffff00,
"model" : "cube",
"texture" : "cubyz:fog"
"texture" : "cubyz:fog/yellow"
}

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x0000ff,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x00ffff,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x00ff00,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0xff00ff,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0xff0000,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0xffff00,
}

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x203860,
}

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x203860,
}

View File

@ -0,0 +1,4 @@
{
"fogDensity" : 0.02,
"fogColor" : 0x203860,
}

View File

@ -6,9 +6,8 @@
"selectable" : false,
"solid" : false,
"transparent" : true,
"hasBackFace" : true,
"absorbedLight" : 0x090501,
"fogDensity" : 0.02,
"fogColor" : 0x203860,
"model" : "cube",
"texture" : {
"time" : 500,

View File

@ -9,8 +9,6 @@ struct AnimationData {
struct TextureData {
uint textureIndices[6];
float fogDensity;
uint fogColor;
};
layout(std430, binding = 0) buffer _animation

View File

@ -20,8 +20,6 @@ layout(location = 0) out vec4 fragColor;
struct TextureData {
uint textureIndices[6];
float fogDensity;
uint fogColor;
};
layout(std430, binding = 1) buffer _textureData
@ -29,6 +27,16 @@ layout(std430, binding = 1) buffer _textureData
TextureData textureData[];
};
struct FogData {
float fogDensity;
uint fogColor;
};
layout(std430, binding = 7) buffer _fogData
{
FogData fogData[];
};
float lightVariation(vec3 normal) {
const vec3 directionalPart = vec3(0, 0.04, 0.08);
const float baseLighting = 0.92;

View File

@ -28,8 +28,6 @@ struct Fog {
struct TextureData {
uint textureIndices[6];
float fogDensity;
uint fogColor;
};
layout(std430, binding = 1) buffer _textureData
@ -37,6 +35,16 @@ layout(std430, binding = 1) buffer _textureData
TextureData textureData[];
};
struct FogData {
float fogDensity;
uint fogColor;
};
layout(std430, binding = 7) buffer _fogData
{
FogData fogData[];
};
float lightVariation(vec3 normal) {
const vec3 directionalPart = vec3(0, 0.04, 0.08);
const float baseLighting = 0.92;
@ -107,9 +115,9 @@ void main() {
float normalVariation = lightVariation(normal);
float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.z);
float dist = zFromDepth(texelFetch(depthTexture, ivec2(gl_FragCoord.xy), 0).r);
float fogDistance = calculateFogDistance(dist, textureData[blockType].fogDensity*densityAdjustment);
float fogDistance = calculateFogDistance(dist, fogData[textureIndex].fogDensity*densityAdjustment);
float airFogDistance = calculateFogDistance(dist, fog.density*densityAdjustment);
vec3 fogColor = unpackColor(textureData[blockType].fogColor);
vec3 fogColor = unpackColor(fogData[textureIndex].fogColor);
vec3 pixelLight = max(light*normalVariation, texture(emissionSampler, textureCoords).r*4);
vec4 textureColor = texture(texture_sampler, textureCoords)*vec4(pixelLight, 1);
float reflectivity = texture(reflectivityAndAbsorptionSampler, textureCoords).a;
@ -119,16 +127,14 @@ void main() {
blendColor.rgb = absorption;
// Fake reflection:
// TODO: Also allow this for opaque pixels.
// TODO: Change this when it rains.
// TODO: Normal mapping.
// TODO: Allow textures to contribute to this term.
textureColor.rgb += (reflectivity*fixedCubeMapLookup(reflect(direction, normal)).xyz)*pixelLight;
textureColor.rgb += texture(emissionSampler, textureCoords).rgb;
blendColor.rgb *= 1 - textureColor.a;
textureColor.a = 1;
if(textureData[blockType].fogDensity == 0.0) {
if(fogData[textureIndex].fogDensity == 0.0) {
// Apply the air fog, compensating for the missing back-face:
applyFrontfaceFog(airFogDistance, fog.color);
} else {

View File

@ -46,8 +46,6 @@ struct VoxelModel {
struct TextureData {
uint textureIndices[6];
float fogDensity;
uint fogColor;
};
layout(std430, binding = 1) buffer _textureData

View File

@ -115,8 +115,7 @@ pub fn register(_: []const u8, id: []const u8, json: JsonElement) u16 {
_gui[size] = allocator.dupe(u8, json.get([]const u8, "GUI", ""));
_transparent[size] = json.get(bool, "transparent", false);
_viewThrough[size] = json.get(bool, "viewThrough", false) or _transparent[size];
const hasFog: bool = json.get(f32, "fogDensity", 0.0) != 0.0;
_hasBackFace[size] = hasFog and _transparent[size];
_hasBackFace[size] = json.get(bool, "hasBackFace", false);
const oreProperties = json.getChild("ore");
if (oreProperties != .JsonNull) {
@ -308,6 +307,8 @@ pub const meshes = struct {
const TextureData = extern struct {
textureIndices: [6]u32,
};
const FogData = extern struct {
fogDensity: f32,
fogColor: u32,
};
@ -325,6 +326,7 @@ pub const meshes = struct {
var emissionTextures: main.List(Image) = undefined;
var reflectivityTextures: main.List(Image) = undefined;
var absorptionTextures: main.List(Image) = undefined;
var textureFogData: main.List(FogData) = undefined;
var arenaForWorld: main.utils.NeverFailingArenaAllocator = undefined;
@ -342,6 +344,7 @@ pub const meshes = struct {
var animationSSBO: ?SSBO = null;
var textureDataSSBO: ?SSBO = null;
var animatedTextureDataSSBO: ?SSBO = null;
var fogSSBO: ?SSBO = null;
var animationShader: Shader = undefined;
var animationUniforms: struct {
@ -371,6 +374,7 @@ pub const meshes = struct {
emissionTextures = main.List(Image).init(main.globalAllocator);
reflectivityTextures = main.List(Image).init(main.globalAllocator);
absorptionTextures = main.List(Image).init(main.globalAllocator);
textureFogData = main.List(FogData).init(main.globalAllocator);
arenaForWorld = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator);
}
@ -384,6 +388,9 @@ pub const meshes = struct {
if(animatedTextureDataSSBO) |ssbo| {
ssbo.deinit();
}
if(fogSSBO) |ssbo| {
ssbo.deinit();
}
animationShader.deinit();
blockTextureArray.deinit();
emissionTextureArray.deinit();
@ -394,6 +401,7 @@ pub const meshes = struct {
emissionTextures.deinit();
reflectivityTextures.deinit();
absorptionTextures.deinit();
textureFogData.deinit();
arenaForWorld.deinit();
}
@ -406,6 +414,7 @@ pub const meshes = struct {
emissionTextures.clearRetainingCapacity();
reflectivityTextures.clearRetainingCapacity();
absorptionTextures.clearRetainingCapacity();
textureFogData.clearRetainingCapacity();
_ = arenaForWorld.reset(.free_all);
}
@ -418,17 +427,21 @@ pub const meshes = struct {
}
pub inline fn fogDensity(block: Block) f32 {
return textureData[block.typ].fogDensity;
return textureFogData.items[textureData[block.typ].textureIndices[0]].fogDensity;
}
pub inline fn fogColor(block: Block) u32 {
return textureData[block.typ].fogColor;
return textureFogData.items[textureData[block.typ].textureIndices[0]].fogColor;
}
fn extendedPath(path: []const u8, pathBuffer: []u8, ending: []const u8) []const u8 {
std.debug.assert(path.ptr == pathBuffer.ptr);
@memcpy(pathBuffer[path.len..][0..ending.len], ending);
return pathBuffer[0..path.len+ending.len];
}
fn readAuxillaryTexture(_path: []const u8, pathBuffer: []u8, ending: []const u8, list: *main.List(Image), default: Image) void {
var path = _path;
@memcpy(pathBuffer[path.len..][0..ending.len], ending);
path.len += ending.len;
const path = extendedPath(_path, pathBuffer, ending);
const texture = Image.readFromFile(arenaForWorld.allocator(), path) catch default;
list.append(texture);
}
@ -469,6 +482,13 @@ pub const meshes = struct {
readAuxillaryTexture(path, &buffer, "_emission.png", &emissionTextures, Image.emptyImage);
readAuxillaryTexture(path, &buffer, "_reflectivity.png", &reflectivityTextures, Image.emptyImage);
readAuxillaryTexture(path, &buffer, "_absorption.png", &absorptionTextures, Image.whiteEmptyImage);
const textureInfoPath = extendedPath(path, &buffer, "_textureInfo.json");
const textureInfoJson = main.files.readToJson(main.stackAllocator, textureInfoPath) catch .JsonNull;
defer textureInfoJson.free(main.stackAllocator);
textureFogData.append(.{
.fogDensity = textureInfoJson.get(f32, "fogDensity", 0.0),
.fogColor = textureInfoJson.get(u32, "fogColor", 0xffffff),
});
} else if(textureInfo == .JsonObject) {
const animationTime = textureInfo.get(i32, "time", 500);
const textures = textureInfo.getChild("textures").toSlice();
@ -502,6 +522,13 @@ pub const meshes = struct {
readAuxillaryTexture(path, &buffer, "_emission.png", &emissionTextures, Image.emptyImage);
readAuxillaryTexture(path, &buffer, "_reflectivity.png", &reflectivityTextures, Image.emptyImage);
readAuxillaryTexture(path, &buffer, "_absorption.png", &absorptionTextures, Image.whiteEmptyImage);
const textureInfoPath = extendedPath(path, &buffer, "_textureInfo.json");
const textureInfoJson = main.files.readToJson(main.stackAllocator, textureInfoPath) catch .JsonNull;
defer textureInfoJson.free(main.stackAllocator);
textureFogData.append(.{
.fogDensity = textureInfoJson.get(f32, "fogDensity", 0.0),
.fogColor = textureInfoJson.get(u32, "fogColor", 0xffffff),
});
}
} else {
return error.NotSpecified;
@ -524,8 +551,6 @@ pub const meshes = struct {
// But textures can be loaded here:
getTextureIndices(json, assetFolder, &textureData[meshes.size].textureIndices);
textureData[meshes.size].fogDensity = json.get(f32, "fogDensity", 0.0);
textureData[meshes.size].fogColor = json.get(u32, "fogColor", 0xffffff);
maxTextureCount[meshes.size] = @intCast(textureIDs.items.len);
@ -574,11 +599,11 @@ pub const meshes = struct {
pub fn generateTextureArray() void {
const c = graphics.c;
blockTextureArray.generate(blockTextures.items, true);
blockTextureArray.generate(blockTextures.items, true, true);
if(main.settings.anisotropicFiltering) {
c.glTexParameterf(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAX_ANISOTROPY, 16);
}
emissionTextureArray.generate(emissionTextures.items, true);
emissionTextureArray.generate(emissionTextures.items, true, false);
if(main.settings.anisotropicFiltering) {
c.glTexParameterf(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAX_ANISOTROPY, 16);
}
@ -599,7 +624,7 @@ pub const meshes = struct {
}
}
}
reflectivityAndAbsorptionTextureArray.generate(reflectivityAndAbsorptionTextures, true);
reflectivityAndAbsorptionTextureArray.generate(reflectivityAndAbsorptionTextures, true, false);
if(main.settings.anisotropicFiltering) {
c.glTexParameterf(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAX_ANISOTROPY, 16);
}
@ -614,11 +639,16 @@ pub const meshes = struct {
if(animatedTextureDataSSBO) |ssbo| {
ssbo.deinit();
}
if(fogSSBO) |ssbo| {
ssbo.deinit();
}
animationSSBO = SSBO.initStatic(AnimationData, animation.items);
animationSSBO.?.bind(0);
textureDataSSBO = SSBO.initStatic(TextureData, textureData[0..meshes.size]);
textureDataSSBO.?.bind(6);
animatedTextureDataSSBO = SSBO.initStatic(TextureData, textureData[0..meshes.size]);
animatedTextureDataSSBO.?.bind(1);
fogSSBO = SSBO.initStatic(FogData, textureFogData.items);
fogSSBO.?.bind(7);
}
};

View File

@ -1467,7 +1467,7 @@ pub const TextureArray = struct {
c.glBindTexture(c.GL_TEXTURE_2D_ARRAY, self.textureID);
}
fn lodColorInterpolation(colors: [4]Color) Color {
fn lodColorInterpolation(colors: [4]Color, alphaCorrection: bool) Color {
var r: [4]f32 = undefined;
var g: [4]f32 = undefined;
var b: [4]f32 = undefined;
@ -1484,8 +1484,8 @@ pub const TextureArray = struct {
var gSum: f32 = 0;
var bSum: f32 = 0;
for(0..4) |i| {
const w = a[i]*a[i];
aSum += w;
const w = if(alphaCorrection) a[i]*a[i] else 1;
aSum += a[i]*a[i];
rSum += w*r[i]*r[i];
gSum += w*g[i]*g[i];
bSum += w*b[i]*b[i];
@ -1494,7 +1494,7 @@ pub const TextureArray = struct {
rSum = @sqrt(rSum)/2;
gSum = @sqrt(gSum)/2;
bSum = @sqrt(bSum)/2;
if(aSum != 0) {
if(alphaCorrection and aSum != 0) {
rSum /= aSum;
gSum /= aSum;
bSum /= aSum;
@ -1503,7 +1503,7 @@ pub const TextureArray = struct {
}
/// (Re-)Generates the GPU buffer.
pub fn generate(self: TextureArray, images: []Image, mipmapping: bool) void {
pub fn generate(self: TextureArray, images: []Image, mipmapping: bool, alphaCorrectMipmapping: bool) void {
var maxWidth: u31 = 0;
var maxHeight: u31 = 0;
for(images) |image| {
@ -1536,7 +1536,7 @@ pub const TextureArray = struct {
for(0..maxWidth) |x| {
for(0..maxHeight) |y| {
const index = x + y*maxWidth;
const imageIndex = (x*image.width)/maxWidth + image.width*(y*image.height)/maxHeight;
const imageIndex = (x*image.width)/maxWidth + image.width*((y*image.height)/maxHeight);
lodBuffer[0][index] = image.imageData[imageIndex];
}
}
@ -1557,7 +1557,7 @@ pub const TextureArray = struct {
lodBuffer[lod-1][index2 + curWidth*2],
lodBuffer[lod-1][index2 + curWidth*2 + 1],
};
lodBuffer[lod][index] = lodColorInterpolation(colors);
lodBuffer[lod][index] = lodColorInterpolation(colors, alphaCorrectMipmapping);
}
}
}