首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八)
2021
11-25

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八)

有段时间没写东西了,最近有点小累啊。最近美术在K动画反映的问题,如果Image组件挂了新材质后,无法在Image上K材质中的效果。

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八) - 雨松MOMO程序研究院 - 1
使用MeshRenderer组件是可以K的,这里简单的给Image材质拓展了一个置灰的效果。如下图所示,MeshRenderer组件就可K材质动画。

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八) - 雨松MOMO程序研究院 - 2

所以我觉得,如果给Image组件同时在绑定MeshRenderer组件。动效师给MeshRenderer组件K动画,在Update中实时将数据同步给Image就可以了。如下图所示,脚本通过读取Image的材质取出所有属性,因为Update不需要将所有数据都同步,这里需要勾选那些数据进行同步。

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八) - 雨松MOMO程序研究院 - 3
如下代码所示

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(Image))]
public class ImageAnim : MonoBehaviour
{
    [System.Serializable]
    public class Data
    {
        public string name;
        public string type;
        public bool enable;
    }
    public List<Data> Property = new List<Data>();

    private Image m_Image;
    private Material m_ImageMat;
    private MeshRenderer m_MeshRenderer;
    private MaterialPropertyBlock m_MaterialPropertyBlock;
    
    private void Awake()
    {
        m_MeshRenderer = GetComponent<MeshRenderer>();
        m_MaterialPropertyBlock = new MaterialPropertyBlock();
        m_Image = GetComponent<Image>();
        m_ImageMat = Instantiate(m_Image.material);
        m_Image.material = m_ImageMat;
    }

    private void LateUpdate()
    {
        if (m_MeshRenderer.HasPropertyBlock())
        {
            m_MeshRenderer.GetPropertyBlock(m_MaterialPropertyBlock);
            foreach (var item in Property)
            {
                if (item.enable)
                {
                    SetValue(item.name, item.type);
                }
            }
        }
     
    }
    void SetValue (string name, string type)
    {
        switch (type)
        {
            case "Color":
                m_Image.color = m_MaterialPropertyBlock.GetColor(name);
                break;
            case "Float":
            case "Range":
                m_Image.material.SetFloat(name,m_MaterialPropertyBlock.GetFloat(name));
                break;
            case "Vector":
                m_Image.material.SetVector(name, m_MaterialPropertyBlock.GetVector(name));
                break;
            default:
                break;
        }

    }
}
#if UNITY_EDITOR
[CustomEditor(typeof(ImageAnim))]
public class MyTestEditor : Editor
{
    ImageAnim myTest;
    MeshRenderer meshrenderer;
    private void OnEnable()
    {
        myTest = (target as ImageAnim);
        meshrenderer = myTest.GetComponent<MeshRenderer>();
    }
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        if (GUILayout.Button("refresh"))
        {
            myTest.Property = new List<ImageAnim.Data>();
            Shader shader = meshrenderer.sharedMaterial.shader;
            int count = shader.GetPropertyCount();
            for (int i = 0; i < count; i++)
            {
                myTest.Property.Add(new ImageAnim.Data() { name = shader.GetPropertyName(i), type = shader.GetPropertyType(i).ToString() });
            }
        }

    }
}
#endif

接着对image的MeshRenderer组件K一个Gray的置灰系数。

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八) - 雨松MOMO程序研究院 - 4

OK 大功告成,image已经可以由动画控制了。

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八) - 雨松MOMO程序研究院 - 5

这个方法只是我的一个思路,我也没有在项目中放手使用,有相关经验的朋友欢迎讨论。

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之Image组件K特殊材质动画的一种方法(一百二十八)》有 7 条评论

  1. hello world说:

    大神的方法果然妙

  2. 说:

    需要做材质的实例化 在编辑器状态下预览就会导致各种资源丢失问题。其实都不需要Meshrender 只需要把材质属性弄出来 用一个脚本包裹一下K帧就行

  3. bzyzhang说:

    使用另外一种方式实现。新建一个脚本,继承BaseMeshEffect。将需要修改的材质属性暴露出来,通过寄存器通道传递给shader处理。这样,做动画时,就可以直接控制暴露出来的变量。参考如下。https://www.zhihu.com/question/437168564/answer/1654231245

留下一个回复

你的email不会被公开。 必填项已用 * 标注。