如何清除铺满屏幕的SpriteRenderer指定世界位置的像素
解决铺满屏幕SpriteRenderer清除指定世界位置像素的坐标偏移问题
问题核心是世界坐标到Sprite纹理像素坐标的映射错误——直接用Camera.WorldToScreenPoint会引入相机屏幕坐标的偏移(比如屏幕原点在左下角,而Sprite的局部坐标基于自身Transform),且距离越远,相机视口的缩放/映射误差越明显。以下是精准的转换方案:
关键思路
跳过屏幕坐标转换,直接将世界坐标映射到Sprite的局部空间,再转换为纹理的像素坐标,完全避免相机带来的偏移。
步骤与代码实现
前提条件
- 使用正交相机(铺满屏幕的SpriteRenderer通常用于2D场景/UI)
- Sprite的纹理已在Inspector中勾选
Read/Write Enabled(否则无法修改像素)
核心代码
using UnityEngine; public class SpritePixelClearer : MonoBehaviour { public SpriteRenderer fullScreenSprite; // 调用此方法清除指定世界位置的像素 public void ClearPixelAtWorld(Vector3 worldPosition) { Sprite sprite = fullScreenSprite.sprite; Texture2D texture = sprite.texture; Transform spriteTransform = fullScreenSprite.transform; // 1. 世界坐标转Sprite局部坐标 Vector3 localPos = spriteTransform.InverseTransformPoint(worldPosition); // 2. 获取Sprite的实际边界尺寸 Bounds bounds = sprite.bounds; float spriteWidth = bounds.size.x; float spriteHeight = bounds.size.y; // 3. 转换为UV坐标(范围0~1) // 基于Pivot在中心的情况:局部坐标范围是[-width/2, width/2],所以加0.5映射到0~1 float u = (localPos.x / spriteWidth) + 0.5f; float v = (localPos.y / spriteHeight) + 0.5f; // 4. 转换为纹理像素坐标(纹理Y轴向下,所以用1-v反转) int pixelX = Mathf.Clamp((int)(u * texture.width), 0, texture.width - 1); int pixelY = Mathf.Clamp((int)((1 - v) * texture.height), 0, texture.height - 1); // 5. 清除像素并应用修改 texture.SetPixel(pixelX, pixelY, Color.clear); texture.Apply(); } }
注意事项
- Pivot适配:如果Sprite的Pivot不是(0.5,0.5),需要调整UV计算逻辑:
- 若Pivot为(0,0):
u = localPos.x / spriteWidth; v = localPos.y / spriteHeight; - 若Pivot为(1,1):
u = 1 - (localPos.x / spriteWidth); v = 1 - (localPos.y / spriteHeight);
- 若Pivot为(0,0):
- 性能优化:如果需要批量清除多个像素,使用
texture.SetPixels()代替单个SetPixel(),减少Apply()的调用次数。 - 透视相机兼容:若必须使用透视相机,需先将世界坐标通过相机投影到视口空间,再映射到Sprite的局部空间,但铺满屏幕的Sprite不推荐用透视相机,会导致拉伸变形。
内容的提问来源于stack exchange,提问作者Lesnier
相关产品推荐
相关产品推荐

