Unity中利用材质本身自发光实现模型物体闪烁效果

本文介绍了一种在Unity中利用材质自发光属性实现物体闪烁效果的方法。通过调整材质的发光亮度和频率,可以创建出逼真的闪烁效果。代码中详细展示了如何控制多个材质的自发光强度,并提供了开始和停止闪烁的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自橙子va:小功能丨Unity中利用材质自发光实现物体闪烁效果,参考自Arvin ZHANG:Unity中利用材质自发光实现物体闪烁效果

项目需要实现模型的闪烁效果,开始通过更改Alpha值实现的闪烁不理想,遂找到了该文章。

代码如下:

using System.Collections;
using UnityEngine;

public class Glint : MonoBehaviour
{
    public Color color = new Color(61 / 255f, 226 / 255f, 131 / 255, 1);

    /// <summary>
    /// 最低发光亮度,取值范围[0,1],需小于最高发光亮度。
    /// </summary>
    [Tooltip("最低发光亮度,取值范围[0,1],需小于最高发光亮度。")]
    [Range(0.0f, 1.0f)]
    public float minBrightness = 0.0f;

    /// <summary>
    /// 最高发光亮度,取值范围[0,1],需大于最低发光亮度。
    /// </summary>
    [Tooltip("最高发光亮度,取值范围[0,1],需大于最低发光亮度。")]
    [Range(0.0f, 1)]
    public float maxBrightness = 0.5f;

    /// <summary>
    /// 闪烁频率,取值范围[0.2,30.0]。
    /// </summary>
    [Tooltip("闪烁频率,取值范围[0.2,30.0]。")]
    [Range(0.2f, 30.0f)]
    public float rate = 1;

    //是否闪烁
    [HideInInspector]
    public bool isGlinting = false;


    [Tooltip("勾选此项则启动时自动开始闪烁")]
    [SerializeField]
    public bool _autoStart = false;

    private float _h, _s, _v;           // 色调,饱和度,亮度
    private float _deltaBrightness;     // 最低最高亮度差
    private Renderer _renderer;

    private Material[] _materials;

    private readonly string _keyword = "_EMISSION";
    private readonly string _colorName = "_EmissionColor";

    private Coroutine _glinting;

    private void Start()
    {
        _renderer = gameObject.GetComponent<MeshRenderer>();

        _materials = _renderer.materials;

        if (_autoStart)
        {
            StartGlinting();
        }
    }
    
    /// <summary>
    /// 校验数据,并保证运行时的修改能够得到应用。
    /// 该方法只在编辑器模式中生效!!!
    /// </summary>
    private void OnValidate()
    {
        // 限制亮度范围
        if (minBrightness < 0 || minBrightness > 1)
        {
            minBrightness = 0.0f;
            Debug.LogError("最低亮度超出取值范围[0, 1],已重置为0。");
        }
        if (maxBrightness < 0 || maxBrightness > 1)
        {
            maxBrightness = 1.0f;
            Debug.LogError("最高亮度超出取值范围[0, 1],已重置为1。");
        }
        if (minBrightness >= maxBrightness)
        {
            minBrightness = 0.0f;
            maxBrightness = 1.0f;
            Debug.LogError("最低亮度[MinBrightness]必须低于最高亮度[MaxBrightness],已分别重置为0/1!");
        }

        // 限制闪烁频率
        if (rate < 0.2f || rate > 30.0f)
        {
            rate = 1;
            Debug.LogError("闪烁频率超出取值范围[0.2, 30.0],已重置为1.0。");
        }

        // 更新亮度差
        _deltaBrightness = maxBrightness - minBrightness;

        // 更新颜色
        // 注意不能使用 _v ,否则在运行时修改参数会导致亮度突变
        float tempV = 0;
        Color.RGBToHSV(color, out _h, out _s, out tempV);
    }

    /// <summary>
    /// 开始闪烁。
    /// </summary>
    public void StartGlinting()
    {
        isGlinting = true;
        if (_materials != null)
        {

            if (_materials.Length > 0)
            {
                for (int i = 0; i < _materials.Length; i++)
                {
                    _materials[i].EnableKeyword(_keyword);
                }

                if (_glinting != null)
                {
                    StopCoroutine(_glinting);
                }
                _glinting = StartCoroutine(IEGlinting());
            }
        }
    }

    /// <summary>
    /// 停止闪烁。
    /// </summary>
    public void StopGlinting()
    {
        isGlinting = false;
        for (int i = 0; i < _materials.Length; i++)
        {
            _materials[i].DisableKeyword(_keyword);
        }

        if (_glinting != null)
        {
            StopCoroutine(_glinting);
        }
    }

    /// <summary>
    /// 控制自发光强度。
    /// </summary>
    /// <returns></returns>
    private IEnumerator IEGlinting()
    {
        Color.RGBToHSV(color, out _h, out _s, out _v);
        _v = minBrightness;
        _deltaBrightness = maxBrightness - minBrightness;

        bool increase = true;
        while (true)
        {
            if (increase)
            {
                _v += _deltaBrightness * Time.deltaTime * rate;
                increase = _v <= maxBrightness;
            }
            else
            {
                _v -= _deltaBrightness * Time.deltaTime * rate;
                increase = _v <= minBrightness;
            }

            for (int i = 0; i < _materials.Length; i++)
            {
                _materials[i].SetColor(_colorName, Color.HSVToRGB(_h, _s, _v));
            }
            yield return null;
        }
    }
    public bool isTrue;
    int index = 1;
    public void OnMouseEnter()
    {
        if (isGlinting && pen.GetComponent<ProbeCtrl>().Num == Num)
        {
            StopGlinting();
            this.gameObject.SetActive(false);
            EventDispatcher.DispatchEvent(EVENT_DIFINE.NextBall,index);
        }
    }
}

 

### 如何在 Unity 中让物体 要在 Unity实现物体的发效果,可以通过调节材质自发属性(Emission)来完成。以下是具体的方法: #### 方法一:通过材质自发实现简单的闪烁效果 1. **创建并设置材质** 首先,在 Unity 的 Project 窗口中右键选择 `Create -> Material` 创建一个新的材质球。选中该材质后,在 Inspector 窗口找到 Emission 属性,并勾选 Enable 复选框[^1]。 2. **配置自发的颜色和强度** 设置 Emission 下的颜色值以及亮度(Brightness)。如果希望物体不显示任何发效果,则可以将亮度调整为 0,此时物体看起来就像未启用自发一样[^2]。 3. **应用到模型上** 将此材质拖拽至场景中的目标对象上,即可看到其表面呈现出指定的发效果。 4. **动态控制发参数** 如果想进一步制作出随时间变化而闪烁效果,可以在脚本里修改材质的颜色或强度。例如下面是一个用于改变发射强弱的小型 C# 脚本示例: ```csharp using UnityEngine; public class FlickeringEffect : MonoBehaviour { public float minIntensity = 0f; // 最低亮度 public float maxIntensity = 5f; // 最高亮度 private Renderer objectRenderer; void Start() { objectRenderer = GetComponent<Renderer>(); } void Update() { if (objectRenderer != null && objectRenderer.material.HasProperty("_EmissionColor")) { Color emissionColor = objectRenderer.material.GetColor("_EmissionColor"); float newIntensity = Mathf.PingPong(Time.time, maxIntensity - minIntensity) + minIntensity; objectRenderer.material.SetColor("_EmissionColor", new Color(emissionColor.r, emissionColor.g, emissionColor.b, newIntensity)); } } } ``` 上述代码会基于 `_PingPong()` 函数生成周期性的波动数值,从而达到一种自然的明暗交替现象。 --- #### 方法二:借助 Shader 实现更复杂的边缘发效果 对于更加高级的需求,比如仅突出显示物体轮廓部分而非整体均匀发亮的情况,可采用定制化着色器方案。这种技术允许开发者精确定义哪些区域应该被照亮及其对应的色彩过渡规律[^3]。 一个典型的应用案例便是模拟霓虹管那样环绕于实体周围的柔和芒带。为此我们需要编写一段 HLSL/GLSL 类型的语言片段嵌入标准 surface shader 结构之中;或者直接选用 Asset Store 上已有的插件资源包加速开发进程。 下面是简化版伪代码框架供参考学习之用: ```hlsl Shader "Custom/EdgeGlow" { Properties { _MainTex ("Texture", 2D) = "white" {} _RimPower ("Rim Power", Range(0.1,8)) = 3.0 _RimColor ("Rim Color", Color) = (0,0.7,1,0) } SubShader { Tags {"Queue"="Transparent" "RenderType"="Opaque"} Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata_t { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 viewDir : TEXCOORD0; }; sampler2D _MainTex; half _RimPower; fixed4 _RimColor; v2f vert(appdata_t IN) { v2f OUT; OUT.pos = UnityObjectToClipPos(IN.vertex); OUT.viewDir = normalize(WorldSpaceViewDir(IN.vertex)); return OUT; } fixed4 frag(v2f IN) : COLOR { half rim = saturate(dot(normalize(IN.viewDir), UNITY_MATRIX_IT_MV[2].xyz)); half glowAmount = pow(rim,_RimPower); return tex2D(_MainTex,fixed2(glowAmount,glowAmount))*_RimColor*glowAmount; } ENDCG } } } ``` 以上 GLSL 片段展示了如何计算视角方向矢量与法线之间的夹角余弦值作为输入变量参与最终像素颜色混合运算过程的一部分逻辑表达式。 --- #### 扩展技巧——多材质组合运用 当面对复杂结构的游戏物件时,单一材质可能无法满足全部需求。这时便引入了多重贴图层叠渲染机制的概念。即同一个网格模型能够绑定若干不同用途的功能性子材料实例共同协作表现更为丰富的视觉特性集合体。例如某些科幻风格角色装备既需要基础金属质感又兼顾局部特殊装饰图案点亮提示等功能点位处理等等情形下尤为适用[^4]。 --- ### 总结 综上所述,无论是简单快速还是精细打磨类型的照特效都可以依靠 Unity 提供的强大工具链轻松达成预期成果展示目的。只需灵活掌握好各个核心组件间相互配合关系原理知识要点即可游刃有余应对各种实际项目挑战难题啦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值