首页 > 技术文章 > Unity一键替换选中物体的材质Editor

qq2351194611 2021-11-24 16:55 原文

1. 编辑器脚本,方便快捷,省时省力(适合替换同一种材质球)

放在Editor文件夹下

直接上代码

 

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// ************************一键替换模型的材质球**********************编辑器脚本************************************
/// 
/// ************************选中你要改变的模型,点击Tools/ChangeNewMaterial按钮即可**************************
/// </summary>
public class ChangeNewMaterial 
{
    [MenuItem("Tools/ChangeNewMaterial")]
    static void ChangeNewMat()
    {
        GameObject obj = Selection.activeGameObject;
        foreach (Renderer it in obj.transform.GetComponentsInChildren<Renderer>())
        {
            Material mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/消融/occ.mat");  //材质球的路径
            Material[] bufMat = new Material[it.sharedMaterials.Length];
            for (int i = 0; i < it.sharedMaterials.Length; i++)
            {
                bufMat[i] = mat;
            }
            it.sharedMaterials = bufMat;
        }
    }

}

上面是编辑器脚本

下面是动态代码脚本

效果:

按钮点击物体切换材质,再次点击恢复原本材质 

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 本脚本挂在摄像机上面
/// 动态变化物体材质球(同一个材质球)
/// </summary>
public class TransparentControl : MonoBehaviour
{
    public class TransparentParam
    {
        public Material[] materials = null;
        public Material[] sharedMats = null;
        public float currentFadeTime = 0;
        public bool isTransparent = true;
    }

    public Transform targetObject = null;   //目标对象
    public float height = 3.0f;             //目标对象Y方向偏移
    private float destTransparent = 0.3f;    //遮挡半透的最终半透强度,
    public float fadeInTime = 1.0f;         //开始遮挡半透时渐变时间
    private int transparentLayer;           //需要遮挡半透的层级
    private Dictionary<Renderer, TransparentParam> transparentDic = new Dictionary<Renderer, TransparentParam>();
    private List<Renderer> clearList = new List<Renderer>();

    public Button button;  //测试按钮

    public bool btnbool = false;
    
    void Start()
    {
        transparentLayer = 1 << 8;//第8层layer

        //按钮点击切换
        button.onClick.AddListener(delegate {
            btnbool = !btnbool;
            if (btnbool)
            {              
                Renderer[] renderers = targetObject.GetComponentsInChildren<Renderer>();
                    foreach (Renderer r in renderers)
                    {
                        AddTransparent(r);
                    }            
            }
            else
            {                          
                RemoveUnuseTransparent();
            }

        });
    }

    void Update()
    {
        if (targetObject == null)
            return;
        UpdateTransparentObject();
        //UpdateRayCastHit();
        //RemoveUnuseTransparent();
    }

    public void UpdateTransparentObject()
    {
        var var = transparentDic.GetEnumerator();
        while (var.MoveNext())
        {
            TransparentParam param = var.Current.Value;
            param.isTransparent = false;
            foreach (var mat in param.materials)
            {
                //颜色自己设置 r g b a
                Color col = mat.GetColor("_Color");
                param.currentFadeTime += Time.deltaTime;
                float t = param.currentFadeTime / fadeInTime;
                col.r = 0;
                col.g = 0.526f;
                col.b = 0.831f;
                col.a = Mathf.Lerp(1, destTransparent, t);
                mat.SetColor("_Color", col);
            }
        }
    }
    //射线检测有没有物体遮挡检测 (比如物体遮挡住人物,被遮挡物体变半透明)
    public void UpdateRayCastHit()
    {
        RaycastHit[] rayHits = null;
        //视线方向为从自身(相机)指向目标位置
        Vector3 targetPos = targetObject.position + new Vector3(0, height, 0);
        Vector3 viewDir = (targetPos - transform.position).normalized;
        Vector3 oriPos = transform.position;
        float distance = Vector3.Distance(oriPos, targetPos);
        Ray ray = new Ray(oriPos, viewDir);
        rayHits = Physics.RaycastAll(ray, distance, transparentLayer);
        //直接在Scene画一条线,方便观察射线
        Debug.DrawLine(oriPos, targetPos, Color.red);
        foreach (var hit in rayHits)
        {
            Renderer[] renderers = hit.collider.GetComponentsInChildren<Renderer>();
            foreach (Renderer r in renderers)
            {
                AddTransparent(r);
            }
        }
    }

    //恢复物体原有材质
    public void RemoveUnuseTransparent()
    {
        clearList.Clear();
        var var = transparentDic.GetEnumerator();
       
        while (var.MoveNext())
        {
            if (var.Current.Value.isTransparent == false)
            {
                //用完后材质实例不会销毁,可以被unloadunuseasset销毁或切场景销毁。
                var.Current.Key.materials = var.Current.Value.sharedMats;
                clearList.Add(var.Current.Key);
            }
        }
        foreach (var v in clearList)
            transparentDic.Remove(v);
    }

    //添加透明材质
    void AddTransparent(Renderer renderer)
    {
        TransparentParam param = null;
        transparentDic.TryGetValue(renderer, out param);
        if (param == null)
        {
            param = new TransparentParam();
            transparentDic.Add(renderer, param);
            //此处顺序不能反,调用material会产生材质实例。
            param.sharedMats = renderer.sharedMaterials;
            param.materials = renderer.materials;
            foreach (var v in param.materials)
            {
                v.shader = Shader.Find("ApcShader/OcclusionTransparent");             
            }
        }
        param.isTransparent = true;
    }

}

 

如果喜欢点个赞吧,感谢 ! ! !

 

推荐阅读