Unity TileMap Shader瓦片接缝灰线问题求助
Hey there! Let's tackle those annoying tile seam lines you're dealing with. You’re absolutely right to suspect floating-point precision issues—this is a super common gotcha with tile mapping shaders, especially when sampling from a spritesheet and doing UV calculations that can drift slightly due to floating-point errors. Let’s break down the fixes step by step:
1. Fix UV & Tile Index Precision
Your current index calculation and UV mod operations are prone to tiny precision errors that can push sampling just over a tile boundary. Here’s how to tighten that up:
- Replace the
%operator withfrac()for more reliable fractional UV extraction—frac()is designed exactly for getting the decimal part of a float, which avoids edge-case errors with mod. - Add a tiny offset when converting UV to integer tile coordinates to prevent floor() from rounding down incorrectly due to precision drift.
- Clamp your tile coordinates to avoid index out-of-bounds issues (which can cause random wrong tiles/seams).
2. Add Texture Padding (The Most Reliable Fix)
Most tile seam gray lines come from texture filtering (like linear filtering) sampling pixels from adjacent tiles in your spritesheet. To fix this, add 1-pixel padding around each tile in your _DiffuseTex spritesheet, matching the edge color of the tile. Then adjust your shader to sample only the inner tile area, skipping the padding.
Modified Shader Fragment Code
Here’s the updated frag function incorporating these fixes:
fixed4 frag (v2f i) : SV_Target { float mapSizeModif = 1.0f / _MapWidth; float worldSizeModif = 1.0f / _WorldWidth; float maskMapSizeModif = 1.0f / _MaskMapWidth; float lightness = 1.0f; // Fix tile index precision with offset + clamping float2 worldUV = i.uv * _WorldWidth; uint x = (uint)clamp(floor(worldUV.x + 0.0001f), 0, _WorldWidth - 1); uint y = (uint)clamp(floor(worldUV.y + 0.0001f), 0, _WorldWidth - 1); uint index = x + y * _WorldWidth; // Use frac() for clean local tile UV instead of mod float2 tileLocalUV = frac(worldUV) * worldSizeModif; uint id = (uint)_allIDs[index]; // Base UV position for the tile in the spritesheet float2 tileBaseUV = float2( mapSizeModif * (id % _MapWidth), mapSizeModif * floor(((float)id)/_MapWidth) ); // Adjust for texture padding (tweak values to match your spritesheet) // Example: 1px padding on a 256x256 spritesheet = 1/256 = 0.00390625 float tilePadding = 0.00390625; float tileScale = (mapSizeModif - 2 * tilePadding) / mapSizeModif; tileLocalUV = tileLocalUV * tileScale + tilePadding; // Combine base and local UVs for final sampling float2 finalUV = tileBaseUV + tileLocalUV; fixed4 col = tex2D(_DiffuseTex, finalUV); col *= _GlobalLumosity; col *= _GlobalHue; col.a = lightness; return col; }
Extra Quick Checks
- Set your
_DiffuseTexwrap mode to Clamp in the Unity inspector—this prevents accidental sampling of distant tiles if UVs drift slightly. - If you can’t add padding right away, switch the texture’s filter mode to Point (no filter)—this eliminates filtering-induced seams but makes tiles look pixelated (use this as a temporary test to confirm the issue is filtering-related).
Key Notes
- The
tilePaddingvalue depends on your spritesheet size: for a 512x512 sheet, 1px padding is1/512 = 0.001953125. Make this a Shader property if you want to adjust it without re-compiling. - The precision fixes alone might reduce seams, but combining them with texture padding will fully resolve the issue in most cases.
内容的提问来源于stack exchange,提问作者Polymer

