Use world-space dithering as well as a better dither matrix to handle transparency in mipmapping/anisotropic filtering (#1641)
- [x] Prototype - [x] Remove old code - [x] ~~Apply this form of dithering to other shaders as well (item drop)~~ → old dither looks better for items and display model - [x] Can we finally remove the dither seed? - [x] Check performance impact → it's slightly (insignificantly) faster even
BIN
assets/cubyz/blocks/textures/dither/1.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/cubyz/blocks/textures/dither/16.png
Normal file
After Width: | Height: | Size: 412 B |
BIN
assets/cubyz/blocks/textures/dither/2.png
Normal file
After Width: | Height: | Size: 75 B |
BIN
assets/cubyz/blocks/textures/dither/32.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/cubyz/blocks/textures/dither/4.png
Normal file
After Width: | Height: | Size: 102 B |
BIN
assets/cubyz/blocks/textures/dither/64.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/cubyz/blocks/textures/dither/8.png
Normal file
After Width: | Height: | Size: 186 B |
@ -7,9 +7,8 @@ layout(location = 3) in vec2 uv;
|
||||
layout(location = 4) flat in vec3 normal;
|
||||
layout(location = 5) flat in int textureIndex;
|
||||
layout(location = 6) flat in int isBackFace;
|
||||
layout(location = 7) flat in int ditherSeed;
|
||||
layout(location = 8) flat in float distanceForLodCheck;
|
||||
layout(location = 9) flat in int opaqueInLod;
|
||||
layout(location = 7) flat in float distanceForLodCheck;
|
||||
layout(location = 8) flat in int opaqueInLod;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
@ -17,6 +16,7 @@ layout(binding = 0) uniform sampler2DArray textureSampler;
|
||||
layout(binding = 1) uniform sampler2DArray emissionSampler;
|
||||
layout(binding = 2) uniform sampler2DArray reflectivityAndAbsorptionSampler;
|
||||
layout(binding = 4) uniform samplerCube reflectionMap;
|
||||
layout(binding = 5) uniform sampler2D ditherTexture;
|
||||
|
||||
layout(location = 5) uniform float reflectionMapSize;
|
||||
layout(location = 6) uniform float contrast;
|
||||
@ -33,29 +33,13 @@ float lightVariation(vec3 normal) {
|
||||
return baseLighting + dot(normal, directionalPart);
|
||||
}
|
||||
|
||||
float ditherThresholds[16] = float[16] (
|
||||
1/17.0, 9/17.0, 3/17.0, 11/17.0,
|
||||
13/17.0, 5/17.0, 15/17.0, 7/17.0,
|
||||
4/17.0, 12/17.0, 2/17.0, 10/17.0,
|
||||
16/17.0, 8/17.0, 14/17.0, 6/17.0
|
||||
);
|
||||
|
||||
ivec2 random1to2(int v) {
|
||||
ivec4 fac = ivec4(11248723, 105436839, 45399083, 5412951);
|
||||
int seed = v.x*fac.x ^ fac.y;
|
||||
return seed*fac.zw;
|
||||
}
|
||||
|
||||
bool passDitherTest(float alpha) {
|
||||
if(opaqueInLod != 0) {
|
||||
if(distanceForLodCheck > lodDistance) return true;
|
||||
float factor = max(0, distanceForLodCheck - (lodDistance - 32.0))/32.0;
|
||||
alpha = alpha*(1 - factor) + factor;
|
||||
}
|
||||
ivec2 screenPos = ivec2(gl_FragCoord.xy);
|
||||
screenPos += random1to2(ditherSeed);
|
||||
screenPos &= 3;
|
||||
return alpha > ditherThresholds[screenPos.x*4 + screenPos.y];
|
||||
return alpha > texture(ditherTexture, uv).r*255.0/256.0 + 0.5/256.0;
|
||||
}
|
||||
|
||||
vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
|
||||
|
@ -7,9 +7,8 @@ layout(location = 3) out vec2 uv;
|
||||
layout(location = 4) flat out vec3 normal;
|
||||
layout(location = 5) flat out int textureIndex;
|
||||
layout(location = 6) flat out int isBackFace;
|
||||
layout(location = 7) flat out int ditherSeed;
|
||||
layout(location = 8) flat out float distanceForLodCheck;
|
||||
layout(location = 9) flat out int opaqueInLod;
|
||||
layout(location = 7) flat out float distanceForLodCheck;
|
||||
layout(location = 8) flat out int opaqueInLod;
|
||||
|
||||
layout(location = 0) uniform vec3 ambientLight;
|
||||
layout(location = 1) uniform mat4 projectionMatrix;
|
||||
@ -84,7 +83,6 @@ void main() {
|
||||
);
|
||||
light = max(sunLight*ambientLight, blockLight)/31;
|
||||
isBackFace = encodedPositionAndLightIndex>>15 & 1;
|
||||
ditherSeed = encodedPositionAndLightIndex & 15;
|
||||
|
||||
textureIndex = textureAndQuad & 65535;
|
||||
int quadIndex = textureAndQuad >> 16;
|
||||
|
@ -7,9 +7,8 @@ layout(location = 3) in vec2 uv;
|
||||
layout(location = 4) flat in vec3 normal;
|
||||
layout(location = 5) flat in int textureIndex;
|
||||
layout(location = 6) flat in int isBackFace;
|
||||
layout(location = 7) flat in int ditherSeed;
|
||||
layout(location = 8) flat in float distanceForLodCheck;
|
||||
layout(location = 9) flat in int opaqueInLod;
|
||||
layout(location = 7) flat in float distanceForLodCheck;
|
||||
layout(location = 8) flat in int opaqueInLod;
|
||||
|
||||
layout(location = 0, index = 0) out vec4 fragColor;
|
||||
layout(location = 0, index = 1) out vec4 blendColor;
|
||||
|
@ -512,6 +512,7 @@ pub const meshes = struct { // MARK: meshes
|
||||
pub var blockTextureArray: TextureArray = undefined;
|
||||
pub var emissionTextureArray: TextureArray = undefined;
|
||||
pub var reflectivityAndAbsorptionTextureArray: TextureArray = undefined;
|
||||
pub var ditherTexture: graphics.Texture = undefined;
|
||||
|
||||
const black: Color = Color{.r = 0, .g = 0, .b = 0, .a = 255};
|
||||
const magenta: Color = Color{.r = 255, .g = 0, .b = 255, .a = 255};
|
||||
@ -525,6 +526,7 @@ pub const meshes = struct { // MARK: meshes
|
||||
blockTextureArray = .init();
|
||||
emissionTextureArray = .init();
|
||||
reflectivityAndAbsorptionTextureArray = .init();
|
||||
ditherTexture = .initFromMipmapFiles("assets/cubyz/blocks/textures/dither/", 64, 0.5);
|
||||
textureIDs = .init(main.globalAllocator);
|
||||
animation = .init(main.globalAllocator);
|
||||
blockTextures = .init(main.globalAllocator);
|
||||
@ -551,6 +553,7 @@ pub const meshes = struct { // MARK: meshes
|
||||
blockTextureArray.deinit();
|
||||
emissionTextureArray.deinit();
|
||||
reflectivityAndAbsorptionTextureArray.deinit();
|
||||
ditherTexture.deinit();
|
||||
textureIDs.deinit();
|
||||
animation.deinit();
|
||||
blockTextures.deinit();
|
||||
|
@ -2307,6 +2307,38 @@ pub const Texture = struct { // MARK: Texture
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn initFromMipmapFiles(pathPrefix: []const u8, largestSize: u31, lodBias: f32) Texture {
|
||||
const self = Texture.init();
|
||||
self.bind();
|
||||
|
||||
const maxLod = std.math.log2_int(u31, largestSize);
|
||||
|
||||
var curSize: u31 = largestSize;
|
||||
while(curSize != 0) : (curSize /= 2) {
|
||||
c.glTexImage2D(c.GL_TEXTURE_2D, maxLod - std.math.log2_int(u31, curSize), c.GL_RGBA8, curSize, curSize, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
}
|
||||
|
||||
curSize = largestSize;
|
||||
while(curSize != 0) : (curSize /= 2) {
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}{}.png", .{pathPrefix, curSize}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
const image = Image.readFromFile(main.stackAllocator, path) catch |err| blk: {
|
||||
std.log.err("Couldn't read image from {s}: {s}", .{path, @errorName(err)});
|
||||
break :blk Image.defaultImage;
|
||||
};
|
||||
defer image.deinit(main.stackAllocator);
|
||||
c.glTexSubImage2D(c.GL_TEXTURE_2D, maxLod - std.math.log2_int(u31, curSize), 0, 0, curSize, curSize, c.GL_RGBA, c.GL_UNSIGNED_BYTE, image.imageData.ptr);
|
||||
}
|
||||
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAX_LOD, maxLod);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST_MIPMAP_LINEAR);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_REPEAT);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_REPEAT);
|
||||
c.glTexParameterf(c.GL_TEXTURE_2D, c.GL_TEXTURE_LOD_BIAS, lodBias);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: Texture) void {
|
||||
c.glDeleteTextures(1, &self.textureID);
|
||||
}
|
||||
|
@ -213,6 +213,8 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
blocks.meshes.emissionTextureArray.bind();
|
||||
c.glActiveTexture(c.GL_TEXTURE2);
|
||||
blocks.meshes.reflectivityAndAbsorptionTextureArray.bind();
|
||||
c.glActiveTexture(c.GL_TEXTURE5);
|
||||
blocks.meshes.ditherTexture.bind();
|
||||
reflectionCubeMap.bindTo(4);
|
||||
|
||||
chunk_meshing.quadsDrawn = 0;
|
||||
|