You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GetPixel引发清洁游戏卡顿,求优化方案及剩余污渍检测方法

清洁类游戏卡顿优化方案(针对GetPixel及污渍检测)

核心问题分析

卡顿根源在于两个高频性能开销操作:

  1. 双层循环内反复调用GetPixel读取纹理像素,每次调用都会触发CPU-GPU数据同步,属于典型的CPU密集型冗余操作
  2. 每次SetPixel后立即执行ApplyTexture,频繁向GPU提交纹理更新请求,造成大量性能浪费

具体优化方案

1. 预缓存纹理像素数组,彻底替代GetPixel

将Brush和污渍蒙版的像素数据一次性加载到CPU数组中,循环时直接访问数组元素,避免反复调用GetPixel:

// 类字段声明:添加缓存数组与相机引用
private Color[] _brushPixels;
private Color[] _dirtMaskPixels;
private Camera _mainCamera;
private float _totalDirtAmount;
private float _currentDirtAmount;

// 在Awake/Start中初始化缓存
private void Awake()
{
    _mainCamera = Camera.main; // 缓存相机,避免每次Raycast重复查找
    _brushPixels = _brush.GetPixels(); // 一次性读取Brush所有像素
    _dirtMaskPixels = _templateDirtMask.GetPixels(); // 一次性读取污渍蒙版所有像素

    // 预计算初始总污渍量(用于后续剩余污渍检测)
    _totalDirtAmount = 0f;
    foreach (Color pixel in _dirtMaskPixels)
    {
        _totalDirtAmount += pixel.g;
    }
    _currentDirtAmount = _totalDirtAmount;
}

修改SetPixel方法中的像素读取逻辑:

private void SetPixel(float textureCoordX, float textureCoordY)
{
    int pixelX = (int)(textureCoordX * _templateDirtMask.width);
    int pixelY = (int)(textureCoordY * _templateDirtMask.height);

    int pixelXOffset = pixelX - (_brush.width / 2);
    int pixelYOffset = pixelY - (_brush.height / 2);

    for (int x = 0; x < _brush.width; x++)
    {
        for (int y = 0; y < _brush.height; y++)
        {
            // 计算数组索引,替代GetPixel的坐标读取
            int brushIndex = x + y * _brush.width;
            int maskIndex = (pixelXOffset + x) + (pixelYOffset + y) * _templateDirtMask.width;
            int dataIndex = maskIndex;

            if (dataIndex > 0 && dataIndex < pixels.Length && brushIndex < _brushPixels.Length && maskIndex < _dirtMaskPixels.Length)
            {
                Color brushPixel = _brushPixels[brushIndex];
                Color maskPixel = _dirtMaskPixels[maskIndex];

                float removedAmount = maskPixel.g - (maskPixel.g * brushPixel.g);
                _currentDirtAmount -= removedAmount;

                // 更新目标像素与缓存的蒙版像素
                pixels[dataIndex] = new Color(0, maskPixel.g * brushPixel.g, 0);
                _dirtMaskPixels[maskIndex] = pixels[dataIndex];
            }
        }
    }
}

2. 合并ApplyTexture调用,减少GPU同步

移除SetPixel方法末尾的ApplyTexture(),改为在触摸操作结束后统一提交纹理更新,避免频繁触发GPU同步:

private void Update()
{
    if (Input.touchCount > 0)
    {
        Touch touch = Input.GetTouch(0);

        if (touch.phase == TouchPhase.Began)
        {
            if (touch.position != prevPosition)
            {
                SetSinglePixel(touch.position);
                prevPosition = touch.position;
            }
        }
        else if (touch.phase == TouchPhase.Moved)
        {
            if (touch.position != prevPosition)
            {
                currentPosition = touch.position;
                Vector2 dif = currentPosition - prevPosition;
                float distance = dif.magnitude;

                if (distance > 36)
                {
                    float count = distance / 36;
                    float ddmo = 36;
                    for (int i = 0; i <= count; i++)
                    {
                        Vector2 gapPoint = Vector2.MoveTowards(prevPosition, currentPosition, ddmo * i);
                        if (Physics.Raycast(_mainCamera.ScreenPointToRay(gapPoint), out RaycastHit hit))
                        {
                            gapPositions.Add(hit.textureCoord);
                        }
                    }
                    SetMultiplePixel(gapPositions);
                    gapPositions.Clear();
                }
                else
                {
                    SetSinglePixel(currentPosition);
                }
                prevPosition = touch.position;
            }
        }
        // 触摸结束时统一提交纹理更新
        else if (touch.phase == TouchPhase.Ended)
        {
            ApplyTexture();
        }
    }
}

如果需要实时预览清洁效果,可以改为每2-3帧调用一次ApplyTexture,平衡性能与视觉体验。

3. 剩余污渍检测优化

直接通过内存中的_currentDirtAmount判断剩余污渍,完全脱离纹理读取操作:

// 检测是否清洁完成(可根据需求调整误差阈值)
bool isCleanComplete = _currentDirtAmount <= 0.1f;
// 获取剩余污渍比例
float remainingDirtRatio = _currentDirtAmount / _totalDirtAmount;

4. 细节优化

  • 移除SetPixel方法中无用的isCheckRemainingTexture参数
  • 简化触摸位置判断逻辑,将touch.position != currentPosition || touch.position != prevPosition改为touch.position != prevPosition,避免无效判断
  • 缓存_templateDirtMask.width、_templateDirtMask.height到类字段,减少循环内属性读取开销

内容的提问来源于stack exchange,提问作者Newboy11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 19:35:22