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

Unity自适应瓦片模式下SpriteRenderer中心区域重复次数计算问题

如何计算Unity SpriteRenderer自适应瓦片模式下中心区域的重复次数

针对你遇到的这个问题,我先梳理下核心逻辑,再修正你的代码——毕竟Unity自适应瓦片的计算规则确实有点绕,尤其是adaptiveModeThreshold的作用容易理解偏差。

首先明确Unity文档里的关键规则:

拉伸值(Stretch Value)范围为0到1,值为1时表示图像被拉伸至原尺寸的两倍,此时该区域开始重复。

也就是说,当中心区域的可用空间比N倍原始中心尺寸多出阈值×原始中心尺寸时,才会触发第N+1次重复,而不是简单做减法后取整。

现有代码的问题分析

  1. 中心区域尺寸计算不够严谨:你通过textureRect.size手动加减边框的方式容易出错,其实可以直接从Sprite的border和纹理尺寸推导更准确。
  2. 自适应模式的重复次数逻辑偏差:你用Mathf.Ceil(countX - sr.adaptiveModeThreshold)的方式,虽然思路接近,但没有完全匹配Unity的触发规则,边界场景下可能出现计算误差。

修正后的完整方案

首先保留你写的FoundInnerTilledRect方法(这个方法的中心修正逻辑是对的,因为不对称边框需要调整Rect中心到局部坐标系原点),然后重构重复次数的计算逻辑:

辅助方法(保留你的实现)

public static void FoundInnerTilledRect(SpriteRenderer sr, out float szTopBorder, out float szBottomBorder, out float szLeftBorder, out float szRightBorder, out Rect innerRect)
{
    var s = sr.sprite;
    float szX = sr.size.x;
    float szY = sr.size.y;
    szTopBorder = s.border.w / s.pixelsPerUnit;
    szBottomBorder = s.border.y / s.pixelsPerUnit;
    szLeftBorder = s.border.x / s.pixelsPerUnit;
    szRightBorder = s.border.z / s.pixelsPerUnit;
    
    innerRect = new Rect();
    innerRect.xMin = szLeftBorder;
    innerRect.xMax = szX - szRightBorder;
    innerRect.yMin = szBottomBorder;
    innerRect.yMax = szY - szTopBorder;
    // 修正中心到SpriteRenderer局部坐标系原点
    innerRect.center = -new Vector2((szRightBorder - szLeftBorder), (szTopBorder - szBottomBorder)) * 0.5f;
}

核心计算方法

public static Vector2 GetAdaptiveTileRepeatCount(SpriteRenderer sr)
{
    Sprite s = sr.sprite;
    if (s == null || sr.drawMode != SpriteDrawMode.Tiled)
    {
        return Vector2.one; // 非瓦片模式默认返回1次
    }

    float topBorder, bottomBorder, leftBorder, rightBorder;
    Rect innerRect;
    FoundInnerTilledRect(sr, out topBorder, out bottomBorder, out leftBorder, out rightBorder, out innerRect);

    // 计算精灵原始中心区域的实际尺寸(转换为米)
    Vector2 originalCenterSize = new Vector2(
        (s.textureRect.width - s.border.x - s.border.z) / s.pixelsPerUnit,
        (s.textureRect.height - s.border.y - s.border.w) / s.pixelsPerUnit
    );

    float countX, countY;

    if (sr.tileMode == SpriteTileMode.Adaptive)
    {
        float availableWidth = innerRect.size.x;
        float availableHeight = innerRect.size.y;

        // 先算基础的整数重复次数(向下取整)
        float baseCountX = Mathf.Floor(availableWidth / originalCenterSize.x);
        float baseCountY = Mathf.Floor(availableHeight / originalCenterSize.y);

        // 计算剩余空间占原始中心尺寸的比例(也就是文档里说的"拉伸值")
        float stretchRatioX = (availableWidth - baseCountX * originalCenterSize.x) / originalCenterSize.x;
        float stretchRatioY = (availableHeight - baseCountY * originalCenterSize.y) / originalCenterSize.y;

        // 如果拉伸值超过阈值,就多一次重复
        countX = baseCountX + (stretchRatioX > sr.adaptiveModeThreshold ? 1 : 0);
        countY = baseCountY + (stretchRatioY > sr.adaptiveModeThreshold ? 1 : 0);
    }
    else
    {
        // 连续瓦片模式:直接取可用空间与原始中心尺寸的比值(向下取整,超过1倍就会重复)
        countX = Mathf.Floor(innerRect.size.x / originalCenterSize.x);
        countY = Mathf.Floor(innerRect.size.y / originalCenterSize.y);
        // 如果尺寸不足原始中心尺寸,默认返回1次(因为会拉伸填充)
        countX = Mathf.Max(countX, 1);
        countY = Mathf.Max(countY, 1);
    }

    return new Vector2(countX, countY);
}

验证方式

你可以通过调整参数测试逻辑正确性:

  • 把adaptiveModeThreshold设为1,此时只有当可用空间≥2倍原始中心尺寸时,重复次数才会从1变成2,完全符合文档描述。
  • 把阈值设为0.5,当可用空间≥1.5倍原始中心尺寸时,重复次数就会增加,这也符合自适应模式避免过度拉伸的设计逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:20:32