diff --git a/assets/shaders/terrain.frag.glsl b/assets/shaders/terrain.frag.glsl index 1a0de9b1..ab2d7cbe 100644 --- a/assets/shaders/terrain.frag.glsl +++ b/assets/shaders/terrain.frag.glsl @@ -50,11 +50,14 @@ float sampleShadowPCF(sampler2DShadow smap, vec3 coords) { } float sampleAlpha(sampler2D tex, vec2 uv) { - // Smooth 5-tap box near chunk edges to hide alpha-map seams; + // Smooth 9-tap box near chunk edges to hide alpha-map seams; // blends gradually to avoid a visible ring at the transition. + // Wider feather (8 texels) makes per-chunk alpha differences + // bleed across the boundary so the chunk grid stops reading + // as a hard step. vec2 edge = min(uv, 1.0 - uv); float border = min(edge.x, edge.y); - float blurWeight = 1.0 - smoothstep(0.5 / 64.0, 3.0 / 64.0, border); + float blurWeight = 1.0 - smoothstep(1.0 / 64.0, 8.0 / 64.0, border); float center = texture(tex, uv).r; if (blurWeight < 0.001) return center; vec2 texel = vec2(1.0 / 64.0); @@ -63,7 +66,11 @@ float sampleAlpha(sampler2D tex, vec2 uv) { avg += texture(tex, uv + vec2( texel.x, 0.0)).r; avg += texture(tex, uv + vec2(0.0, -texel.y)).r; avg += texture(tex, uv + vec2(0.0, texel.y)).r; - avg *= 0.2; + avg += texture(tex, uv + vec2(-texel.x, -texel.y)).r; + avg += texture(tex, uv + vec2( texel.x, -texel.y)).r; + avg += texture(tex, uv + vec2(-texel.x, texel.y)).r; + avg += texture(tex, uv + vec2( texel.x, texel.y)).r; + avg *= 1.0 / 9.0; return mix(center, avg, blurWeight); } diff --git a/src/pipeline/terrain_mesh.cpp b/src/pipeline/terrain_mesh.cpp index cf95335b..11bc90a2 100644 --- a/src/pipeline/terrain_mesh.cpp +++ b/src/pipeline/terrain_mesh.cpp @@ -237,8 +237,12 @@ std::vector TerrainMeshGenerator::generateVertices(const MapChunk } // Texture coordinates: world-aligned so patterns don't reset per chunk. - // Keep one texture repeat per chunk (matches prior scale). - constexpr float texScale = 1.0f / CHUNK_SIZE; + // Tile each texture 4× per chunk (one repeat every ~8 yards) so the + // texture's own pattern noise breaks up the chunk grid rather than + // syncing with it. At 1 repeat/chunk the per-chunk alpha differences + // read as obvious 33-yard squares; at 4× the pattern is small enough + // that the eye no longer locks onto the chunk boundary. + constexpr float texScale = 4.0f / CHUNK_SIZE; vertex.texCoord[0] = -vertex.position[1] * texScale; vertex.texCoord[1] = -vertex.position[0] * texScale;