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

Unity逐GameObject调整材质Tiling出现编辑模式材质泄漏报错如何解决

解决方案

方案1:使用MaterialPropertyBlock(推荐,无材质实例、无泄漏、性能最优)

这个方案完全不需要创建独立材质实例,通过Unity内置的MaterialPropertyBlock为单个Renderer设置独有的纹理缩放参数,所有墙体可以共用同一个sharedMaterial,不会触发警告,也不会有材质泄漏问题,同时支持静态合批,性能远优于创建多份材质实例。

[ExecuteInEditMode]
public class AutoTiler : MonoBehaviour
{
    public float xScaleMult = 1;
    public float yScaleMult = 1;
    
    private MaterialPropertyBlock _propBlock;
    private MeshRenderer _renderer;
    private Vector3 _lastScale;
    private static readonly int MainTexScaleId = Shader.PropertyToID("_MainTex_ST");

    void OnEnable()
    {
        _propBlock ??= new MaterialPropertyBlock();
        _renderer ??= GetComponent<MeshRenderer>();
        _lastScale = transform.localScale;
        UpdateTiling();
    }

    void Update()
    {
        // 只有缩放变化时才更新,避免每帧无效计算
        if (transform.localScale != _lastScale)
        {
            _lastScale = transform.localScale;
            UpdateTiling();
        }
    }

    void UpdateTiling()
    {
        // 从Renderer获取当前的PropertyBlock,避免覆盖其他已设置的参数
        _renderer.GetPropertyBlock(_propBlock);
        Vector2 tiling = new Vector2(
            Mathf.Max(transform.localScale.x, transform.localScale.z) * xScaleMult, 
            transform.localScale.y * yScaleMult
        );
        // _MainTex_ST的xy是Tiling,zw是Offset,这里Offset保持默认0即可
        _propBlock.SetVector(MainTexScaleId, new Vector4(tiling.x, tiling.y, 0, 0));
        // 赋值回Renderer
        _renderer.SetPropertyBlock(_propBlock);
    }
}

该方案完全不会触发编辑模式的材质泄漏警告,不需要管理材质实例生命周期,每个墙体的Tiling参数完全独立,共用同一份原始材质即可。


方案2:主动管理独立材质实例(适用于需要修改更多材质参数的场景)

之前代码报错的核心原因是在编辑模式下访问renderer.material会触发Unity的隐式实例化逻辑,内置的泄漏检查会识别到这个非托管的实例,我们只需要主动管理材质实例的创建和销毁即可规避警告:

[ExecuteInEditMode]
public class AutoTiler : MonoBehaviour
{
    public float xScaleMult = 1;
    public float yScaleMult = 1;
    [SerializeField, HideInInspector] private Material _customMaterial;
    private MeshRenderer _renderer;
    private Vector3 _lastScale;

    void OnEnable()
    {
        _renderer ??= GetComponent<MeshRenderer>();
        // 初始化自定义材质
        if (_customMaterial == null)
        {
            // 主动实例化,不通过.material隐式创建
            _customMaterial = new Material(_renderer.sharedMaterial);
            _customMaterial.name = $"{_renderer.sharedMaterial.name}_AutoTiled_{gameObject.GetInstanceID()}";
            // 标记为跟随场景保存,避免编辑模式下丢失
            _customMaterial.hideFlags = HideFlags.HideInHierarchy | HideFlags.DontSaveInBuild;
            // 赋值给sharedMaterial,不会触发隐式实例化警告
            _renderer.sharedMaterial = _customMaterial;
        }
        _lastScale = transform.localScale;
        UpdateTiling();
    }

    void OnDestroy()
    {
        // 显式销毁材质实例,避免泄漏
        if (_customMaterial != null)
        {
            DestroyImmediate(_customMaterial);
        }
    }

    void Update()
    {
        if (transform.localScale != _lastScale)
        {
            _lastScale = transform.localScale;
            UpdateTiling();
        }
    }

    void UpdateTiling()
    {
        _customMaterial.mainTextureScale = new Vector2(
            Mathf.Max(transform.localScale.x, transform.localScale.z) * xScaleMult, 
            transform.localScale.y * yScaleMult
        );
    }
}

该方案主动控制材质实例的创建、标记、销毁流程,不会触发Unity的内置警告,也不会出现材质泄漏,同时保留了独立材质实例的需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:06:07