Unity等距Tilemap多精灵排序失效问题(PPU/锚点一致仍异常)
Unity等距Tilemap排序冲突解决方案
问题背景
精灵资源规格
- 尺寸:所有精灵均为500x500像素
- 像素每单位(PPU):均设为512
- 锚点(Pivot):统一自定义锚点(250, 375)(对应立方体顶部菱形的底部中心)
- 几何形状:精灵形状和元数据完全一致,仅颜色和文件名不同
问题现象
- 当三个插槽使用同一精灵(如仅草地)时,区块渲染正常,Y轴排序符合预期。
- 一旦使用不同文件(Grass.png、Sand.png、Water.png),排序完全失效,背景Tile频繁覆盖前景Tile,出现图层混乱。
生成器代码
using UnityEngine; using UnityEngine.Tilemaps; using UnityEngine.Rendering; using System.Collections.Generic; public class WorldGenerator : MonoBehaviour { [Header("Sprites")] public Sprite waterSprite; public Sprite sandSprite; public Sprite grassSprite; [Header("Settings")] public int chunkSize = 16; private Dictionary<string, Tile> tileCache = new Dictionary<string, Tile>(); void Start() { // Setting up global sorting for isometry GraphicsSettings.transparencySortMode = TransparencySortMode.CustomAxis; GraphicsSettings.transparencySortAxis = new Vector3(0, 1, -1); GenerateSingleChunk(); } void GenerateSingleChunk() { GameObject oldGrid = GameObject.Find("IsoGrid"); if (oldGrid) DestroyImmediate(oldGrid); GameObject gridObj = new GameObject("IsoGrid"); Grid grid = gridObj.AddComponent<Grid>(); grid.cellLayout = GridLayout.CellLayout.Isometric; // Size for 500px sprites with 512 PPU float sw = 500f / 512f; grid.cellSize = new Vector3(sw, sw * 0.5f, 1f); GameObject chunkObj = new GameObject("Chunk_Main"); chunkObj.transform.SetParent(gridObj.transform); Tilemap tilemap = chunkObj.AddComponent<Tilemap>(); TilemapRenderer tr = chunkObj.AddComponent<TilemapRenderer>(); tilemap.tileAnchor = Vector3.zero; tr.mode = TilemapRenderer.Mode.Individual; tr.sortOrder = TilemapRenderer.SortOrder.TopRight; for (int x = 0; x < chunkSize; x++) { for (int y = 0; y < chunkSize; y++) { tilemap.SetTile(new Vector3Int(x, y, 0), GetRandomTile()); } } } Tile GetRandomTile() { float r = Random.value; if (r < 0.33f) return GetCachedTile("Water", waterSprite); if (r < 0.66f) return GetCachedTile("Sand", sandSprite); return GetCachedTile("Grass", grassSprite); } Tile GetCachedTile(string id, Sprite s) { if (!tileCache.ContainsKey(id)) { Tile t = ScriptableObject.CreateInstance<Tile>(); t.sprite = s; tileCache[id] = t; } return tileCache[id]; } }
问题截图


可行解决方案
1. 统一Tile的共享材质
不同Sprite导入时自动生成的材质可能存在渲染队列或参数差异,导致排序计算异常。
- 手动创建一个透明材质(渲染队列设为Transparent),在Inspector中赋值给脚本的
sharedTileMaterial变量。 - 修改
GetCachedTile方法,给所有Tile绑定该共享材质:
public Material sharedTileMaterial; // 在Inspector赋值 Tile GetCachedTile(string id, Sprite s) { if (!tileCache.ContainsKey(id)) { Tile t = ScriptableObject.CreateInstance<Tile>(); t.sprite = s; t.material = sharedTileMaterial; // 统一材质 tileCache[id] = t; } return tileCache[id]; }
2. 切换Tilemap渲染模式为Chunk
当前Individual模式会让每个Tile单独渲染,不同Sprite可能触发不同的排序批次。改为Chunk模式后,Tilemap会合并Tile渲染,统一计算排序:
tr.mode = TilemapRenderer.Mode.Chunk;
3. 调整透明排序轴与添加Sorting Group
- 尝试调整全局透明排序轴为等距视角常用的深度计算方向:
GraphicsSettings.transparencySortAxis = new Vector3(1, 1, 0);
- 给Chunk_Main GameObject添加
SortingGroup组件,强制统一组内元素的排序规则,避免不同Sprite的渲染批次干扰。
4. 给不同类型Tile设置Z轴偏移
通过微小的Z轴偏移强制指定绘制顺序,保证草地>沙地>水域:
Tile GetCachedTile(string id, Sprite s) { if (!tileCache.ContainsKey(id)) { Tile t = ScriptableObject.CreateInstance<Tile>(); t.sprite = s; // 根据Tile类型设置Z偏移,值越大越晚绘制(显示在上方) float zOffset = id switch { "Water" => -0.01f, "Sand" => 0f, "Grass" => 0.01f, _ => 0f }; t.transform = Matrix4x4.Translate(new Vector3(0, 0, zOffset)); tileCache[id] = t; } return tileCache[id]; }
5. 统一Sprite导入设置
打开所有Sprite的Import Settings,确保以下参数完全一致:
- Mesh Type(建议设为Full Rect)
- Extrude Edges
- Filter Mode
- Wrap Mode
避免Unity为不同Sprite生成不同网格数据,导致排序计算异常。
内容的提问来源于stack exchange,提问作者AlexFX
相关产品推荐
相关产品推荐

