From 3bc32eed7d7b578a757b1c8dae9c7cb78cc85412 Mon Sep 17 00:00:00 2001 From: JellySquid Date: Fri, 17 Jan 2025 18:43:27 -0600 Subject: [PATCH] Adjust tex coord epsilon depending on atlas size This fixes some texture precision issues with very large atlases, and with hardware that has limited sub-texel precision. --- .../gl/shader/uniform/GlUniformFloat2v.java | 22 +++++++++++++++++++ .../chunk/shader/DefaultShaderInterface.java | 19 ++++++++++++++++ .../render/texture/TextureAtlasAccessor.java | 9 ++++---- .../shaders/blocks/block_layer_opaque.vsh | 3 ++- .../sodium/shaders/include/chunk_vertex.glsl | 10 ++++----- 5 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat2v.java diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat2v.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat2v.java new file mode 100644 index 0000000000..428458f8cc --- /dev/null +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat2v.java @@ -0,0 +1,22 @@ +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; + +import org.lwjgl.opengl.GL30C; + +public class GlUniformFloat2v extends GlUniform { + public GlUniformFloat2v(int index) { + super(index); + } + + @Override + public void set(float[] value) { + if (value.length != 2) { + throw new IllegalArgumentException("value.length != 2"); + } + + GL30C.glUniform2fv(this.index, value); + } + + public void set(float x, float y) { + GL30C.glUniform2f(this.index, x, y); + } +} diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/DefaultShaderInterface.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/DefaultShaderInterface.java index 1ce8947477..bfa6ace1d9 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/DefaultShaderInterface.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/DefaultShaderInterface.java @@ -1,10 +1,14 @@ package net.caffeinemc.mods.sodium.client.render.chunk.shader; import com.mojang.blaze3d.platform.GlStateManager; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat2v; import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat3v; import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformInt; import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformMatrix4f; import net.caffeinemc.mods.sodium.client.util.TextureUtil; +import net.caffeinemc.mods.sodium.mixin.core.render.texture.TextureAtlasAccessor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlas; import org.joml.Matrix4fc; import org.lwjgl.opengl.GL32C; @@ -20,6 +24,7 @@ public class DefaultShaderInterface implements ChunkShaderInterface { private final GlUniformMatrix4f uniformModelViewMatrix; private final GlUniformMatrix4f uniformProjectionMatrix; private final GlUniformFloat3v uniformRegionOffset; + private final GlUniformFloat2v uniformTexCoordShrink; // The fog shader component used by this program in order to setup the appropriate GL state private final ChunkShaderFogComponent fogShader; @@ -28,6 +33,7 @@ public DefaultShaderInterface(ShaderBindingContext context, ChunkShaderOptions o this.uniformModelViewMatrix = context.bindUniform("u_ModelViewMatrix", GlUniformMatrix4f::new); this.uniformProjectionMatrix = context.bindUniform("u_ProjectionMatrix", GlUniformMatrix4f::new); this.uniformRegionOffset = context.bindUniform("u_RegionOffset", GlUniformFloat3v::new); + this.uniformTexCoordShrink = context.bindUniform("u_TexCoordShrink", GlUniformFloat2v::new); this.uniformTextures = new EnumMap<>(ChunkShaderTextureSlot.class); this.uniformTextures.put(ChunkShaderTextureSlot.BLOCK, context.bindUniform("u_BlockTex", GlUniformInt::new)); @@ -38,9 +44,22 @@ public DefaultShaderInterface(ShaderBindingContext context, ChunkShaderOptions o @Override // the shader interface should not modify pipeline state public void setupState() { + // TODO: Bind to these textures directly rather than using fragile RenderSystem state this.bindTexture(ChunkShaderTextureSlot.BLOCK, TextureUtil.getBlockTextureId()); this.bindTexture(ChunkShaderTextureSlot.LIGHT, TextureUtil.getLightTextureId()); + var textureAtlas = (TextureAtlasAccessor) Minecraft.getInstance() + .getTextureManager() + .getTexture(TextureAtlas.LOCATION_BLOCKS); + + // Direct3D specifies "at least 16.8 fixed-point precision" for texture fetches. Most OpenGL-capable graphics + // cards are Direct3D-capable as well, so this would likely be a safe bet. However, mobile GPUs (and notably + // Apple's own hardware) only seems to provide 16.4 fixed-point precision. + this.uniformTexCoordShrink.set( + (1.0f / textureAtlas.getWidth()) / 32.0f, + (1.0f / textureAtlas.getHeight()) / 32.0f + ); + this.fogShader.setup(); } diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/texture/TextureAtlasAccessor.java b/common/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/texture/TextureAtlasAccessor.java index f95d1f8f59..7f9a6b060b 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/texture/TextureAtlasAccessor.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/texture/TextureAtlasAccessor.java @@ -1,15 +1,14 @@ package net.caffeinemc.mods.sodium.mixin.core.render.texture; import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import java.util.Map; - @Mixin(TextureAtlas.class) public interface TextureAtlasAccessor { @Accessor - Map getTexturesByName(); + int getWidth(); + + @Accessor + int getHeight(); } diff --git a/common/src/main/resources/assets/sodium/shaders/blocks/block_layer_opaque.vsh b/common/src/main/resources/assets/sodium/shaders/blocks/block_layer_opaque.vsh index e281de1eae..089e895101 100644 --- a/common/src/main/resources/assets/sodium/shaders/blocks/block_layer_opaque.vsh +++ b/common/src/main/resources/assets/sodium/shaders/blocks/block_layer_opaque.vsh @@ -19,6 +19,7 @@ out float v_FragDistance; uniform int u_FogShape; uniform vec3 u_RegionOffset; +uniform vec2 u_TexCoordShrink; uniform sampler2D u_LightTex; // The light map texture sampler @@ -47,7 +48,7 @@ void main() { // Add the light color to the vertex color, and pass the texture coordinates to the fragment shader v_Color = _vert_color * texture(u_LightTex, _vert_tex_light_coord); - v_TexCoord = _vert_tex_diffuse_coord; + v_TexCoord = _vert_tex_diffuse_coord - (_vert_tex_diffuse_coord_bias * u_TexCoordShrink); v_MaterialMipBias = _material_mip_bias(_material_params); #ifdef USE_FRAGMENT_DISCARD diff --git a/common/src/main/resources/assets/sodium/shaders/include/chunk_vertex.glsl b/common/src/main/resources/assets/sodium/shaders/include/chunk_vertex.glsl index 3ce9949258..e392ffa901 100644 --- a/common/src/main/resources/assets/sodium/shaders/include/chunk_vertex.glsl +++ b/common/src/main/resources/assets/sodium/shaders/include/chunk_vertex.glsl @@ -3,6 +3,7 @@ vec3 _vert_position; // The block texture coordinate of the vertex vec2 _vert_tex_diffuse_coord; +vec2 _vert_tex_diffuse_coord_bias; // The light texture coordinate of the vertex vec2 _vert_tex_light_coord; @@ -28,10 +29,6 @@ const uint TEXTURE_MAX_VALUE = TEXTURE_MAX_COORD - 1u; const float VERTEX_SCALE = 32.0 / float(POSITION_MAX_COORD); const float VERTEX_OFFSET = -8.0; -// The amount of inset the texture coordinates from the edges of the texture, to avoid texture bleeding -const float TEXTURE_FUZZ_AMOUNT = 1.0 / 64.0; -const float TEXTURE_GROW_FACTOR = (1.0 - TEXTURE_FUZZ_AMOUNT) / TEXTURE_MAX_COORD; - in uvec2 a_Position; in vec4 a_Color; in uvec2 a_TexCoord; @@ -49,13 +46,14 @@ vec2 _get_texcoord() { } vec2 _get_texcoord_bias() { - return mix(vec2(-TEXTURE_GROW_FACTOR), vec2(TEXTURE_GROW_FACTOR), bvec2(a_TexCoord >> TEXTURE_BITS)); + return mix(vec2(-1.0), vec2(1.0), bvec2(a_TexCoord >> TEXTURE_BITS)); } void _vert_init() { _vert_position = (_deinterleave_u20x3(a_Position) * VERTEX_SCALE) + VERTEX_OFFSET; _vert_color = a_Color; - _vert_tex_diffuse_coord = _get_texcoord() + _get_texcoord_bias(); + _vert_tex_diffuse_coord = _get_texcoord(); + _vert_tex_diffuse_coord_bias = _get_texcoord_bias(); _vert_tex_light_coord = vec2(a_LightAndData.xy) / vec2(256.0);