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

Unity UIToolkit中Material为空,无法设置自定义属性求助

问题:Unity UIToolkit自定义着色器属性运行时无法修改

在Unity UIToolkit中使用带有自定义属性_RevealAmount的材质,UIBuilder中拖动调整该属性可正常实现图片水平显隐效果,但运行时通过C#代码修改MaterialDefinition的该属性完全无效,且打印Material对象为null。

原代码

public class MyUI : MonoBehaviour
{
    private UIDocument ui;

    private void OnEnable()
    {
        ui = GetComponent<UIDocument>();
        var root = ui.rootVisualElement;
        var renderTexture = root.Q<VisualElement>("renderTexture");

        Debug.Log(renderTexture.style.unityMaterial.value.material); // 输出Null

        DOVirtual.Float(0f, 1f, 5f, v =>
        {
            renderTexture.style.unityMaterial.value.SetFloat("_RevealAmount", v); // 无效果
            //renderTexture.style.unityMaterial.value.SetFloat("RevealAmount", v); // 无效果
            //Debug.Log("Reveal amount: " + v); // 正常输出0到1的往复值
        }).SetLoops(-1, LoopType.Yoyo);
    }
}

问题根源

UIToolkit的MaterialDefinition只是材质的引用定义,并非运行时实际实例化的Material对象。直接操作style.unityMaterial.value无法修改运行时的材质状态,因为它不指向实际的渲染材质实例。

解决办法

步骤说明

  1. 获取运行时材质实例:通过MaterialDefinition.GetMaterialInstance()方法获取可修改的材质实例。
  2. 缓存实例避免重复获取:提升性能,减少不必要的实例创建。
  3. 修改属性后强制UI重绘:调用VisualElement.MarkDirtyRepaint()触发UI重新渲染,让属性修改生效。

修改后的代码

public class MyUI : MonoBehaviour
{
    private UIDocument ui;
    private Material targetMaterial;

    private void OnEnable()
    {
        ui = GetComponent<UIDocument>();
        var root = ui.rootVisualElement;
        var renderTextureElement = root.Q<VisualElement>("renderTexture");

        var materialDef = renderTextureElement.style.unityMaterial.value;
        if (materialDef != null)
        {
            targetMaterial = materialDef.GetMaterialInstance();
            Debug.Log("获取到材质实例: " + targetMaterial);
        }

        if (targetMaterial != null)
        {
            DOVirtual.Float(0f, 1f, 5f, v =>
            {
                targetMaterial.SetFloat("_RevealAmount", v);
                renderTextureElement.MarkDirtyRepaint(); // 强制UI重绘
            }).SetLoops(-1, LoopType.Yoyo);
        }
        else
        {
            Debug.LogError("无法获取有效的材质实例");
        }
    }

    private void OnDisable()
    {
        // 释放材质实例,避免内存泄漏
        if (targetMaterial != null)
        {
            MaterialDefinition.ReleaseMaterialInstance(targetMaterial);
            targetMaterial = null;
        }
    }
}

额外注意事项

  • 确保VisualElement的名称"renderTexture"与UIBuilder中的元素名称完全一致。
  • 着色器中的属性名称必须为_RevealAmount(带下划线),与代码中的调用严格对应。
  • 在组件禁用时释放材质实例,避免不必要的内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 17:42:37