Unity UGUI Image使用图集透明度点击过滤BUG

将Sprite打入图集时会默认去掉边缘的alpha=0的部分

Unity的Image.IsRaycastLocationValid在判断alphaHitTestMinimumThreshold的时候会使用图集中的点判断alpha而不是原Sprite中的点

所以会导致无法正确获取到alpha,要修复这个BUG可以重写Image类

主要是添加了这段代码 其他都是原装的

csharp 复制代码
 //计算local在图集中的位置
 Rect spriteRect = overrideSprite.textureRect;
 local.x = local.x - overrideSprite.textureRectOffset.x + spriteRect.x;
 local.y = local.y - overrideSprite.textureRectOffset.y + spriteRect.y;
 //判断是否在当前图的范围内
 if (!overrideSprite.textureRect.Contains(local))
 {
     return false;
 }

其实只重写了IsRaycastLocationValid方法,但是要访问private方法 只能拷贝出来了

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class OverrideImage : Image
{
    
    private void _PreserveSpriteAspectRatio(ref Rect rect, Vector2 spriteSize)
    {
        var spriteRatio = spriteSize.x / spriteSize.y;
        var rectRatio = rect.width / rect.height;

        if (spriteRatio > rectRatio)
        {
            var oldHeight = rect.height;
            rect.height = rect.width * (1.0f / spriteRatio);
            rect.y += (oldHeight - rect.height) * rectTransform.pivot.y;
        }
        else
        {
            var oldWidth = rect.width;
            rect.width = rect.height * spriteRatio;
            rect.x += (oldWidth - rect.width) * rectTransform.pivot.x;
        }
    }
    private Vector4 _GetAdjustedBorders(Vector4 border, Rect adjustedRect)
    {
        Rect originalRect = rectTransform.rect;

        for (int axis = 0; axis <= 1; axis++)
        {
            float borderScaleRatio;

            // The adjusted rect (adjusted for pixel correctness)
            // may be slightly larger than the original rect.
            // Adjust the border to match the adjustedRect to avoid
            // small gaps between borders (case 833201).
            if (originalRect.size[axis] != 0)
            {
                borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis];
                border[axis] *= borderScaleRatio;
                border[axis + 2] *= borderScaleRatio;
            }

            // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size.
            // In order to avoid artefacts with overlapping borders, we scale the borders down to fit.
            float combinedBorders = border[axis] + border[axis + 2];
            if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0)
            {
                borderScaleRatio = adjustedRect.size[axis] / combinedBorders;
                border[axis] *= borderScaleRatio;
                border[axis + 2] *= borderScaleRatio;
            }
        }
        return border;
    }
    
    private Vector2 _MapCoordinate(Vector2 local, Rect rect)
    {
        Rect spriteRect = overrideSprite.rect;
        if (type == Type.Simple || type == Type.Filled)
            return new Vector2(spriteRect.position.x + local.x * spriteRect.width / rect.width, spriteRect.position.y + local.y * spriteRect.height / rect.height);

        Vector4 border = overrideSprite.border;
        Vector4 adjustedBorder = _GetAdjustedBorders(border / pixelsPerUnit, rect);

        for (int i = 0; i < 2; i++)
        {
            if (local[i] <= adjustedBorder[i])
                continue;

            if (rect.size[i] - local[i] <= adjustedBorder[i + 2])
            {
                local[i] -= (rect.size[i] - spriteRect.size[i]);
                continue;
            }

            if (type == Type.Sliced)
            {
                float lerp = Mathf.InverseLerp(adjustedBorder[i], rect.size[i] - adjustedBorder[i + 2], local[i]);
                local[i] = Mathf.Lerp(border[i], spriteRect.size[i] - border[i + 2], lerp);
            }
            else
            {
                local[i] -= adjustedBorder[i];
                local[i] = Mathf.Repeat(local[i], spriteRect.size[i] - border[i] - border[i + 2]);
                local[i] += border[i];
            }
        }

        return local + spriteRect.position;
    }
    
    public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
    {
        if (alphaHitTestMinimumThreshold <= 0)
            return true;

        if (alphaHitTestMinimumThreshold > 1)
            return false;

        if (overrideSprite == null)
            return true;

        Vector2 local;
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local))
            return false;

        Rect rect = GetPixelAdjustedRect();

        if (preserveAspect)
            _PreserveSpriteAspectRatio(ref rect, new Vector2(overrideSprite.texture.width, overrideSprite.texture.height));

        // Convert to have lower left corner as reference point.
        local.x += rectTransform.pivot.x * rect.width;
        local.y += rectTransform.pivot.y * rect.height;

        local = _MapCoordinate(local, rect);
        
        //计算local在图集中的位置
        Rect spriteRect = overrideSprite.textureRect;
        local.x = local.x - overrideSprite.textureRectOffset.x + spriteRect.x;
        local.y = local.y - overrideSprite.textureRectOffset.y + spriteRect.y;
        //判断是否在当前图的范围内
        if (!overrideSprite.textureRect.Contains(local))
        {
            return false;
        }
        
        // Convert local coordinates to texture space.
        float x = local.x / overrideSprite.texture.width;
        float y = local.y / overrideSprite.texture.height;
    
        try
        {
            return overrideSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold;
        }
        catch (UnityException e)
        {
            Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
            return true;
        }
    }
}
相关推荐
ellis197035 分钟前
Unity插件SafeArea Helper适配异形屏详解
unity
nnsix2 小时前
Unity Physics.Raycast的 QueryTriggerInteraction枚举作用
unity·游戏引擎
地狱为王2 小时前
Cesium for Unity叠加行政区划线
unity·gis·cesium
小贺儿开发11 小时前
Unity3D 八大菜系连连看
游戏·unity·互动·传统文化
在路上看风景11 小时前
25. 屏幕像素和纹理像素不匹配
unity
王家视频教程图书馆12 小时前
修复服务端500相应,修复客户端上传文件.tmp 服务端接受不到文件bug
bug
ۓ明哲ڪ12 小时前
Unity功能——创建新脚本时自动添加自定义头注释
unity·游戏引擎
熬夜敲代码的小N12 小时前
Unity大场景卡顿“急救包”:从诊断到落地的全栈优化方案
java·unity·游戏引擎
qq_4017004112 小时前
Qt开发过程中遇到哪些经典的bug
qt·bug
派葛穆14 小时前
Unity-realvirtual-S7通讯快速配置(未完结)
unity·游戏引擎