Unity中如何检测Sprite透明区域 仅在精灵可见部分生成预制体
Unity Sprite非透明区域方块填充实现方案
核心问题原因
之前的GetPixel方案失效,本质是四个逻辑错误:
- 直接将世界坐标强转作为纹理像素坐标使用,未做坐标空间转换,采样位置完全不匹配
- 未考虑Sprite的Pivot偏移、在源纹理/图集中的区域偏移、像素与单位的缩放比例
- 直接判断像素不等于
Color.clear的逻辑鲁棒性差,纹理压缩产生的噪点、半透明抗锯齿边缘都会导致判断错误 - 未处理纹理未开启可读权限的情况
实现步骤
1. 前置资源配置
选中目标Sprite的源纹理,在Inspector面板做如下配置:
- 将
Texture Type设置为Sprite (2D and UI) - 勾选Read/Write Enabled选项
- 纹理压缩格式选择无压缩格式,避免压缩导致alpha通道值偏差
- 点击Apply保存配置
2. 核心实现代码
提前缓存所有公共参数,循环内完成坐标转换、越界判断、透明度校验三个核心逻辑:
// 提前缓存组件和Sprite参数,避免循环内重复获取 SpriteRenderer playerSr = player.GetComponent<SpriteRenderer>(); Sprite targetSprite = playerSr.sprite; Texture2D targetTex = targetSprite.texture; Rect spriteTextureRect = targetSprite.rect; Vector2 spritePivot = targetSprite.pivot; float ppu = targetSprite.pixelsPerUnit; float newY = startVertical; while (newY < endVertical) { float newX = startHorizontal; while (newX < endHorizontal) { Vector3 spawnPos = new Vector3(newX, newY, 0); // 世界坐标转Sprite本地坐标 Vector3 localPos = playerSr.transform.InverseTransformPoint(spawnPos); // 本地坐标转纹理像素坐标 float px = localPos.x * ppu + spritePivot.x + spriteTextureRect.x; float py = localPos.y * ppu + spritePivot.y + spriteTextureRect.y; // 越界直接跳过 if (px < 0 || px >= targetTex.width || py < 0 || py >= targetTex.height) { newX += fillerWidth + 0.1f; continue; } // 采样像素,通过alpha阈值判断是否为可见区域,阈值可根据需求调整 Color pixel = targetTex.GetPixel((int)px, (int)py); if (pixel.a > 0.1f) { Instantiate(filler, spawnPos, Quaternion.identity); } newX += fillerWidth + 0.1f; } newY += fillerHeight + 0.1f; }
3. 可选优化&兼容方案
- 性能优化:不要在循环中逐次调用
GetPixel,循环前先用GetPixels32()一次性读取整个Sprite区域的像素数据存入数组,循环中直接通过索引查询数组值,性能可提升数十倍 - 图集兼容:上述坐标转换逻辑自动适配图集模式,
sprite.rect已包含当前Sprite在图集纹理中的位置偏移,无需额外处理 - 不可读纹理兼容:如果不想修改源纹理的导入配置,可在运行时创建可读纹理副本,实现代码如下:
Texture2D CreateReadableTextureCopy(Texture2D source) { RenderTexture tempRT = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.sRGB); Graphics.Blit(source, tempRT); Texture2D readableCopy = new Texture2D(source.width, source.height); RenderTexture preRT = RenderTexture.active; RenderTexture.active = tempRT; readableCopy.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0); readableCopy.Apply(); RenderTexture.active = preRT; RenderTexture.ReleaseTemporary(tempRT); return readableCopy; }
- 填充精度调整:如果需要每个方块精确对齐像素,可将fillerWidth、fillerHeight设置为
1/ppu,间隔设为0即可
效果参考
- 带透明区域的原始Sprite:

- 错误的全边界填充效果:

- 目标非透明区域填充效果:

内容的提问来源于stack exchange,提问作者Martin Mbae
相关产品推荐
相关产品推荐

