当前位置: 首页 > article >正文

【Unity高级】如何动态调整物体透明度

本文介绍了如何设置及动态调整物体的透明度。

一、手动设置的方法

我们先来看下如何手动设置物体的透明度。

物体的透明与否是通过材质来设置的。只有我们把具有透明度的材质指给物体的渲染器(Render),物体就被设置成相应的透明度了。

看一下上面半透明(左二)物体的材质设置。

(1)将材质的Surface Type设置为Transparent,Blending Mode设置为Alpha。

(2)点开Base Map,(3)调整A值(Alpha通道)来改变透明度

(4)也可以调整物体表面光滑度,调整材质效果(比如玻璃)。

二、使用代码设置

如果我们想在运行时动态调整物体的透明度的话,可以通过设置材质的相关参数来实现。

两个核心方法如下:

1. SetMaterialOpaque() - 设置材质为不透明

当透明度值大于或等于 1 时,调用此方法将材质设置为不透明。

    private void SetMaterialOpaque()
    {
        targetMaterial.SetFloat("_Surface", 0); // 设置材质为不透明,0 = Opaque
        targetMaterial.SetOverrideTag("RenderType", "Opaque"); // 设置渲染类型标签为不透明
        targetMaterial.SetInt("_Blend", 0); // 设置混合模式为不透明
        targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); // 设置源混合模式为 One
        targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); // 设置目标混合模式为 Zero
        targetMaterial.SetInt("_ZWrite", 1); // 启用深度缓冲区写入(不透明物体需要写入深度缓冲区)
        targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry; // 设置渲染队列为几何体渲染队列(不透明物体)
        targetMaterial.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); // 禁用透明表面类型关键字

        Color color = targetMaterial.GetColor("_BaseColor"); // 获取材质的基础颜色
        color.a = 1f; // 设置透明度为 1,完全不透明
        targetMaterial.SetColor("_BaseColor", color); // 更新材质的颜色
    }
  • 设置材质属性
    • targetMaterial.SetFloat("_Surface", 0):将材质的 _Surface 属性设置为 0,表示材质为不透明(Opaque)。

    • targetMaterial.SetOverrideTag("RenderType", "Opaque"):设置渲染类型标签为不透明。

    • targetMaterial.SetInt("_Blend", 0)targetMaterial.SetInt("_SrcBlend", 1)targetMaterial.SetInt("_DstBlend", 0):这些设置指定了混合模式为不透明(没有透明度混合)。

    • targetMaterial.SetInt("_ZWrite", 1):启用 Z 缓冲区写入(不透明物体需要写入深度缓冲区)。

    • targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry:设置渲染队列为几何体渲染队列(不透明物体通常在此队列中渲染)。

    • Color color = targetMaterial.GetColor("_BaseColor"); color.a = 1f; targetMaterial.SetColor("_BaseColor", color);:设置材质的颜色透明度为 1,表示完全不透明。

2. SetMaterialTransparent(float alpha) - 设置材质为透明

当透明度值小于 1 时,调用此方法将材质设置为透明,并根据透明度值调整材质的透明度。

 private void SetMaterialTransparent(float alpha)
    {
        targetMaterial.SetFloat("_Surface", 1); // 设置材质为透明,1 = Transparent
        targetMaterial.SetOverrideTag("RenderType", "Transparent"); // 设置渲染类型标签为透明
        targetMaterial.SetInt("_Blend", 1); // 设置混合模式为透明
        targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); // 设置源混合模式为源透明度
        targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); // 设置目标混合模式为 1 - 源透明度
        targetMaterial.SetInt("_ZWrite", 0); // 禁用深度缓冲区写入(透明物体通常不写入深度缓冲区)
        targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; // 设置渲染队列为透明物体渲染队列
        targetMaterial.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); // 启用透明表面类型关键字

        Color color = targetMaterial.GetColor("_BaseColor"); // 获取材质的基础颜色
        color.a = alpha; // 设置透明度为传入的 alpha 值
        targetMaterial.SetColor("_BaseColor", color); // 更新材质的颜色
    }
  • 设置材质属性

    • targetMaterial.SetFloat("_Surface", 1):将材质的 _Surface 属性设置为 1,表示材质为透明(Transparent)。
    • targetMaterial.SetOverrideTag("RenderType", "Transparent"):设置渲染类型标签为透明。
    • targetMaterial.SetInt("_Blend", 1)targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha)targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha):这些设置指定了透明物体的混合模式(使用源透明度和目标透明度的反向混合)。
    • targetMaterial.SetInt("_ZWrite", 0):禁用 Z 缓冲区写入(透明物体通常不写入深度缓冲区,以便能够看到背后的物体)。
    • targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent:设置渲染队列为透明物体渲染队列。
    • targetMaterial.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"):启用透明表面类型的关键词。
  • 透明度值调整

    • Color color = targetMaterial.GetColor("_BaseColor"); color.a = alpha; targetMaterial.SetColor("_BaseColor", color);:根据传入的 alpha 值(透明度)设置材质的颜色透明度。alpha 在 0 到 1 之间,0 表示完全透明,1 表示完全不透明。

动态调整的话,核心就是在触发时,通过调整color.a的值来实现。

三、完整代码

上面示例中使用滑动条来调整透明度的完整代码如下:

using UnityEngine;
using UnityEngine.UI;

public class MaterialTransparencySlider : MonoBehaviour
{
    private Material targetMaterial; // 当前对象的材质
    private MeshRenderer meshRenderer; // 用于控制影子
    public Slider transparencySlider; // Slider 控件

    public Text textOpacity;

  void Start()
    {
        // 获取 MeshRenderer
        meshRenderer = GetComponent<MeshRenderer>();
        if (meshRenderer != null)
        {
            targetMaterial = meshRenderer.material; // 获取材质实例
        }
        else
        {
            Debug.LogError("未找到 GameObject 上的 MeshRenderer。");
            return;
        }

        if (transparencySlider != null)
        {
            // 监听 Slider 值变化事件
            transparencySlider.onValueChanged.AddListener(UpdateMaterialTransparency);

            // 初始化材质状态
            UpdateMaterialTransparency(transparencySlider.value);
        }
        else
        {
            Debug.LogError("未分配透明度滑动条 (Slider)。");
        }
    }

    /// <summary>
    /// 根据 Slider 的值动态更新材质透明度
    /// </summary>
    /// <param name="value">Slider 的当前值(范围 0-1)</param>
    public void UpdateMaterialTransparency(float value)
    {
        if (targetMaterial == null || meshRenderer == null) return;

        if (value >= 1f)
        {
            // 设置材质为完全不透明
            SetMaterialOpaque();
        }
        else
        {
            // 设置材质为透明,并调整透明度
            SetMaterialTransparent(value);
        }

        // 更新影子状态
        UpdateShadows(value);

        // 更新text
        textOpacity.text = $"透明度={value * 100}";
    }

    /// <summary>
    /// 设置材质为完全不透明
    /// </summary>
    private void SetMaterialOpaque()
    {
        targetMaterial.SetFloat("_Surface", 0); // 设置材质为不透明,0 = Opaque
        targetMaterial.SetOverrideTag("RenderType", "Opaque"); // 设置渲染类型标签为不透明
        targetMaterial.SetInt("_Blend", 0); // 设置混合模式为不透明
        targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); // 设置源混合模式为 One
        targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); // 设置目标混合模式为 Zero
        targetMaterial.SetInt("_ZWrite", 1); // 启用深度缓冲区写入(不透明物体需要写入深度缓冲区)
        targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry; // 设置渲染队列为几何体渲染队列(不透明物体)
        targetMaterial.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); // 禁用透明表面类型关键字

        Color color = targetMaterial.GetColor("_BaseColor"); // 获取材质的基础颜色
        color.a = 1f; // 设置透明度为 1,完全不透明
        targetMaterial.SetColor("_BaseColor", color); // 更新材质的颜色
    }


    /// <summary>
    /// 设置材质为透明,并动态调整透明度
    /// </summary>
    /// <param name="alpha">透明度值(0-1)</param>
    private void SetMaterialTransparent(float alpha)
    {
        targetMaterial.SetFloat("_Surface", 1); // 设置材质为透明,1 = Transparent
        targetMaterial.SetOverrideTag("RenderType", "Transparent"); // 设置渲染类型标签为透明
        targetMaterial.SetInt("_Blend", 1); // 设置混合模式为透明
        targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); // 设置源混合模式为源透明度
        targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); // 设置目标混合模式为 1 - 源透明度
        targetMaterial.SetInt("_ZWrite", 0); // 禁用深度缓冲区写入(透明物体通常不写入深度缓冲区)
        targetMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; // 设置渲染队列为透明物体渲染队列
        targetMaterial.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); // 启用透明表面类型关键字

        Color color = targetMaterial.GetColor("_BaseColor"); // 获取材质的基础颜色
        color.a = alpha; // 设置透明度为传入的 alpha 值
        targetMaterial.SetColor("_BaseColor", color); // 更新材质的颜色
    }

    /// <summary>
    /// 动态更新影子显示状态
    /// </summary>
    /// <param name="alpha">透明度值(0-1)</param>
    private void UpdateShadows(float alpha)
    {
        if (alpha <= 0f)
        {
            // 完全透明时禁用影子
            meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        }
        else
        {
            // 非完全透明时启用影子
            meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
        }
    }

    private void OnDestroy()
    {
        // 移除监听事件以避免内存泄漏
        if (transparencySlider != null)
        {
            transparencySlider.onValueChanged.RemoveListener(UpdateMaterialTransparency);
        }
    }
}

四、存在的问题

1. 可见问题:球1是手动设置的完全透明的材质,它与球4透明度为0时的状态还是有区别的。球1是可见的,而球4是完全不可见的。

2. 影子问题:球1和球2,是手动设置的透明材质,没有影子。球4在动态设置为透明材质时,仍然会有影子。最后透明度为0时影子消失,是在代码里处理的。

这两上问题有待进一下研究。


http://www.kler.cn/a/428821.html

相关文章:

  • 麦田物语学习笔记:创建TransitionManager控制人物场景切换
  • Windows11电脑总是一闪一闪的,黑一下亮一些怎么解决
  • 有限元分析学习——Anasys Workbanch第一阶段笔记(13)网格单元分类、物理场与自由度概念
  • 调试Hadoop源代码
  • Cloud Foundry,K8S,Mesos Marathon弹性扩缩容特性对比
  • 战场物联网:通信挑战与最新解决方案综述
  • Linux-Regmap实验
  • Go database/sql包源码分析
  • ShardingSphere 数据库中间件
  • k8s 为什么需要Pod?
  • 高级java每日一道面试题-2024年12月05日-JVM篇-什么是TLAB?
  • 计算机键盘的演变 | 键盘键名称及其功能 | 键盘指法
  • 软件无线电安全之GNU Radio基础(下)
  • 英文论文翻译成中文,怎样翻译更地道?
  • 【开源免费】基于Vue和SpringBoot的高校学科竞赛平台(附论文)
  • 普通算法——一维前缀和
  • k8s-Informer概要解析(2)
  • Mybatis-plus 多租户插件
  • 如何使用Apache HttpClient来执行GET、POST、PUT和DELETE请求
  • 【JAVA】Java高级:数据库监控与调优:SQL调优与执行计划的分析
  • MySQL(四)--索引
  • QNX系统的编译过程
  • 【uniapp】swiper切换时,v-for重新渲染页面导致文字在视觉上的拉扯问题
  • 40分钟学 Go 语言高并发:【实战】分布式缓存系统
  • Go学习:变量
  • 重生之我在21世纪学C++—关系、条件、逻辑操作符