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.
@ -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"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x0000ff,
|
||||
}
|
BIN
assets/cubyz/blocks/textures/fog/cyan.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x00ffff,
|
||||
}
|
BIN
assets/cubyz/blocks/textures/fog/green.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x00ff00,
|
||||
}
|
BIN
assets/cubyz/blocks/textures/fog/magenta.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0xff00ff,
|
||||
}
|
BIN
assets/cubyz/blocks/textures/fog/red.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0xff0000,
|
||||
}
|
BIN
assets/cubyz/blocks/textures/fog/yellow.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0xffff00,
|
||||
}
|
4
assets/cubyz/blocks/textures/water.png_textureInfo.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x203860,
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x203860,
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x203860,
|
||||
}
|
@ -6,9 +6,8 @@
|
||||
"selectable" : false,
|
||||
"solid" : false,
|
||||
"transparent" : true,
|
||||
"hasBackFace" : true,
|
||||
"absorbedLight" : 0x090501,
|
||||
"fogDensity" : 0.02,
|
||||
"fogColor" : 0x203860,
|
||||
"model" : "cube",
|
||||
"texture" : {
|
||||
"time" : 500,
|
||||
|
@ -9,8 +9,6 @@ struct AnimationData {
|
||||
|
||||
struct TextureData {
|
||||
uint textureIndices[6];
|
||||
float fogDensity;
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -46,8 +46,6 @@ struct VoxelModel {
|
||||
|
||||
struct TextureData {
|
||||
uint textureIndices[6];
|
||||
float fogDensity;
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) buffer _textureData
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|