unity中动态处理模型透明或材质的方法

时间:2024-03-11 11:46:14

1.改shader

using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 枚举Shader4种状态类型
/// </summary>
public enum RenderingMode
{
    Opaque,
    Cutout,
    Fade,
    Transparent,
}

public class StandardModelObj
{
    public GameObject m_go;
    public Material m_material;
    public Color m_color;
    public RenderingMode m_mode;

    public StandardModelObj (GameObject go, Material material,Color color, RenderingMode mode)
    {
        m_go = go;
        m_material = material;
        m_color = color;
        m_mode = mode;
    }
}

/// <summary>
/// 用于动态修改Shader
/// </summary>
public class StandardModel
{
    //
    public static Shader FadeShader = null;
    public static Shader StandardShader = null;
    private static Color m_startColor;
    private static Dictionary<int, List<StandardModelObj>> standardModelObjDic = new Dictionary<int, List<StandardModelObj>>();

    /// <summary>
    /// 具体处理材质Shader函数
    /// </summary>
    /// <param name="material"></param>
    /// <param name="renderingMode"></param>
    private static void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
    {
        switch (renderingMode)
        {
            case RenderingMode.Opaque:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case RenderingMode.Cutout:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case RenderingMode.Fade:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case RenderingMode.Transparent:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }

    /// <summary>
    /// 非Opaquet模式
    /// </summary>
    /// <param name="root"></param>
    /// <param name="mode"></param>
    /// <param name="aphaneityValue"></param>
    private static void SetAllMode(GameObject root, RenderingMode mode, float aphaneityValue)
    {
        if (root.GetComponent<MeshRenderer>())
        {
            MeshRenderer mesh = root.GetComponent<MeshRenderer>();
            for (int i = 0; i < mesh.materials.Length; i++)
            {
                RenderingMode tempMode = GetRenderMode(mesh.materials[i]);
                Color color = mesh.materials[i].color;
                StandardModelObj standardModelObj = new StandardModelObj(root, mesh.materials[i], color, tempMode);
                mesh.materials[i].color = new Color(color.r, color.g, color.b, aphaneityValue);
                SetMaterialRenderingMode(mesh.materials[i], mode);
                int key = root.GetInstanceID();
                List<StandardModelObj> temp;
                if (standardModelObjDic.TryGetValue(key, out temp))
                {
                    temp.Add(standardModelObj);
                }
                else
                {
                    temp = new List<StandardModelObj>();
                    temp.Add(standardModelObj);
                    standardModelObjDic[key] = temp;
                }
            }
        }

        if (root.transform.childCount > 0)
        {
            for (int i = 0; i < root.transform.childCount; i++)
            {
                GameObject child = root.transform.GetChild(i).gameObject;
                SetAllMode(child, mode, aphaneityValue);
            }
        }
    }

    private static RenderingMode GetRenderMode(Material material)
    {
        RenderingMode mode = RenderingMode.Opaque;
        int SrcBlend = material.GetInt("_SrcBlend");
        int DstBlend = material.GetInt("_DstBlend");
        int ZWrite = material.GetInt("_ZWrite");

        if (SrcBlend == (int)UnityEngine.Rendering.BlendMode.One && DstBlend == (int)UnityEngine.Rendering.BlendMode.Zero && ZWrite == 1 && material.renderQueue == -1)
        {
            mode = RenderingMode.Opaque;
        }
        else if (SrcBlend == (int)UnityEngine.Rendering.BlendMode.One && DstBlend == (int)UnityEngine.Rendering.BlendMode.Zero && ZWrite == 1 && material.renderQueue == 2450)
        {
            mode = RenderingMode.Cutout;
        }
        else if (SrcBlend == (int)UnityEngine.Rendering.BlendMode.SrcAlpha && DstBlend == (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha && ZWrite == 0 && material.renderQueue == 3000)
        {
            mode = RenderingMode.Fade;
        }
        else if (SrcBlend == (int)UnityEngine.Rendering.BlendMode.One && DstBlend == (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha && ZWrite == 0 && material.renderQueue == 3000)
        {
            mode = RenderingMode.Transparent;
        }
        return mode;
    }

    private static void Restore(GameObject go)
    {
        foreach (KeyValuePair<int, List<StandardModelObj>> item in standardModelObjDic)
        {
            for (int i = 0; i < item.Value.Count; i++)
            {
                if (go == item.Value[i].m_go)
                {
                    SetMaterialRenderingMode(item.Value[i].m_material, item.Value[i].m_mode);
                    item.Value[i].m_material.color = item.Value[i].m_color;
                }
            }
        }
    }

    private static void RestoreGameObject(GameObject go)
    {
        StandardModel.Restore(go);
        for (int i = 0; i < go.transform.childCount; i++)
        {
            Restore(go.transform.GetChild(i).gameObject);
        }
    }


    private static Shader GetFadeShader()
    {
        if (FadeShader == null)
        {
            FadeShader = Shader.Find("CustomShader/AlphaBlendWithBothSide");
        }
        return FadeShader;
    }

    private static Shader GetStandardShader()
    {
        if (StandardShader == null)
        {
            StandardShader = Shader.Find("Standard");
        }
        return StandardShader;
    }

    public static void SetFadeByCustomShader(GameObject root, float aphaneityValue)
    {
        Shader shader = GetFadeShader();
        MeshRenderer[] meshRenderers = root.GetComponentsInChildren<MeshRenderer>(true);
        MeshRenderer meshRenderer;
        for (int i = 0; i < meshRenderers.Length; i++)
        {
            meshRenderer = meshRenderers[i];
            for (int j = 0; j < meshRenderer.materials.Length; j++)
            {
                meshRenderer.materials[j].shader = shader;
                meshRenderer.materials[j].SetFloat("_AlphaScale", aphaneityValue);
            }
        }
    }
    public static void SetStandard(GameObject root)
    {
        Shader shader = GetStandardShader();
        MeshRenderer[] meshRenderers = root.GetComponentsInChildren<MeshRenderer>(true);
        MeshRenderer meshRenderer;
        for (int i = 0; i < meshRenderers.Length; i++)
        {
            meshRenderer = meshRenderers[i];
            for (int j = 0; j < meshRenderer.materials.Length; j++)
            {
                meshRenderer.materials[j].shader = shader;
                meshRenderer.materials[j].SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                meshRenderer.materials[j].SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                meshRenderer.materials[j].SetInt("_ZWrite", 1);
                meshRenderer.materials[j].DisableKeyword("_ALPHATEST_ON");
                meshRenderer.materials[j].DisableKeyword("_ALPHABLEND_ON");
                meshRenderer.materials[j].DisableKeyword("_ALPHAPREMULTIPLY_ON");
                meshRenderer.materials[j].renderQueue = -1;
            }
        }
    }

}

shader的代码(一个设置透明的简单shader)

// Upgrade NOTE: replaced \'_Object2World\' with \'unity_ObjectToWorld\'
// Upgrade NOTE: replaced \'mul(UNITY_MATRIX_MVP,*)\' with \'UnityObjectToClipPos(*)\'

Shader "CustomShader/AlphaBlendWithBothSide" {
    Properties{
        _Color("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex("Main Tex", 2D) = "white" {}
        _AlphaScale("Alpha Scale", Range(0, 1)) = 1
    }
        SubShader{
            Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}

            Pass {
                Tags { "LightMode" = "ForwardBase" }

                // First pass renders only back faces 
                Cull Front

                ZWrite Off
                Blend SrcAlpha OneMinusSrcAlpha

                CGPROGRAM

                #pragma vertex vert
                #pragma fragment frag

                #include "Lighting.cginc"

                fixed4 _Color;
                sampler2D _MainTex;
                float4 _MainTex_ST;
                fixed _AlphaScale;

                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                    float4 texcoord : TEXCOORD0;
                };

                struct v2f {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                    float2 uv : TEXCOORD2;
                };

                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);

                    o.worldNormal = UnityObjectToWorldNormal(v.normal);

                    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                    return o;
                }

                fixed4 frag(v2f i) : SV_Target {
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                    fixed4 texColor = tex2D(_MainTex, i.uv);

                    fixed3 albedo = texColor.rgb * _Color.rgb;

                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                    fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));

                    return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
                }

                ENDCG
            }

            Pass {
                Tags { "LightMode" = "ForwardBase" }

                // Second pass renders only front faces 
                Cull Back

                ZWrite Off
                Blend SrcAlpha OneMinusSrcAlpha

                CGPROGRAM

                #pragma vertex vert
                #pragma fragment frag

                #include "Lighting.cginc"

                fixed4 _Color;
                sampler2D _MainTex;
                float4 _MainTex_ST;
                fixed _AlphaScale;

                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                    float4 texcoord : TEXCOORD0;
                };

                struct v2f {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                    float2 uv : TEXCOORD2;
                };

                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);

                    o.worldNormal = UnityObjectToWorldNormal(v.normal);

                    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                    return o;
                }

                fixed4 frag(v2f i) : SV_Target {
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                    fixed4 texColor = tex2D(_MainTex, i.uv);

                    fixed3 albedo = texColor.rgb * _Color.rgb;

                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                    fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));

                    return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
                }

                ENDCG
            }
        }
            FallBack "Transparent/VertexLit"
}

3.设置如下

 

 

 

 

4.用法

StandardModel.SetFadeByCustomShader(this.gameObject, 0.1f);
//StandardModel.SetAllMode((this.gameObject, RenderingMode.Fade, 0.1f);
//StandardModel.SetAllMode(this.gameObject, RenderingMode.Opaque, 1);

 

另外一种方法,改材质球

        private static Dictionary<int, NeedCustomMaterialObj> m_NeedCustomMaterialObjDic = new Dictionary<int, NeedCustomMaterialObj>();
        /// <summary>
        /// 修obj使用指定的材质球
        /// </summary>
        /// <param name="root">模型节点</param>
        /// <param name="customMaterial">自定义材质球</param>
        /// <param name="tag">需要剔除的模型的tag</param>
        public static void InitCustomMaterialByMeshRenderer(GameObject root, Material customMaterial, string tag = "")
        {
            MeshRenderer[] renders = root.transform.GetComponentsInChildren<MeshRenderer>(true);
            foreach (var item in renders)
            {
                if (item.tag == tag)
                {
                    continue;
                }
                int key = item.GetInstanceID();
                if (!m_NeedCustomMaterialObjDic.ContainsKey(key))
                {
                    NeedCustomMaterialObj needCustomMaterialObj = new NeedCustomMaterialObj();
                    needCustomMaterialObj.m_render = item;
                    needCustomMaterialObj.m_materials = new Material[item.materials.Length];
                    m_NeedCustomMaterialObjDic.Add(key, needCustomMaterialObj);

                    for (int i = 0; i < item.materials.Length; i++)
                    {
                        needCustomMaterialObj.m_materials[i] = new Material(item.materials[i]);
                        item.materials[i].CopyPropertiesFromMaterial(customMaterial);
                    }
                }

                  else
                  {
                   for (int i = 0; i < item.materials.Length; i++)
                   {
                     m_NeedCustomMaterialObjDic[key].m_materials[i] = new Material(item.materials[i]);
                     item.materials[i].CopyPropertiesFromMaterial(customMaterial);
                   }
                  }


            }
        }

        public static void InitCustomMaterialByTansform(GameObject root, Material customMaterial, string tag = "")
        {
            if (root.tag == tag)
            {
                return;
            }
            if (root.GetComponent<MeshRenderer>())
            {
                MeshRenderer renderer = root.GetComponent<MeshRenderer>();
                int key = root.GetInstanceID();
                if (!m_NeedCustomMaterialObjDic.ContainsKey(key))
                {
                    NeedCustomMaterialObj needCustomMaterialObj = new NeedCustomMaterialObj();
                    needCustomMaterialObj.m_render = renderer;
                    needCustomMaterialObj.m_materials = new Material[renderer.materials.Length];
                    m_NeedCustomMaterialObjDic.Add(key, needCustomMaterialObj);

                    for (int i = 0; i < renderer.materials.Length; i++)
                    {
                        needCustomMaterialObj.m_materials[i] = new Material(renderer.materials[i]);
                        renderer.materials[i].CopyPropertiesFromMaterial(customMaterial);
                    }
                }
         

                 else
                 {
                  for (int i = 0; i < item.materials.Length; i++)
                  {
                    m_NeedCustomMaterialObjDic[key].m_materials[i] = new Material(item.materials[i]);
                    item.materials[i].CopyPropertiesFromMaterial(customMaterial);
                  }
                 }


            }

            if (root.transform.childCount > 0)
            {
                for (int i = 0; i < root.transform.childCount; i++)
                {
                    GameObject child = root.transform.GetChild(i).gameObject;
                    InitCustomMaterialByTansform(child, customMaterial, tag);
                }
            }
        }

        public static void RestoreCustomMaterialByMeshRenderer()
        {
            foreach (var item in m_NeedCustomMaterialObjDic)
            {
                item.Value.Set();
            }
        }


 

    public class NeedCustomMaterialObj
    {
        public MeshRenderer m_render;
        public Material[] m_materials;

        public void Set()
        {
            for (int i = 0; i < m_render.materials.Length; i++)
            {
                m_render.materials[i].CopyPropertiesFromMaterial(m_materials[i]);
            }
        }
    }

用法如下:

public Material m_customMat;
public GameObject m_root;

private void Start()
{
//参数为:设置指定材质球的对象,材质球,剔除的tag
Tool.InitCustomMaterialByMeshRenderer(m_root, m_customMat, "NoFade");
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Tool.RestoreCustomMaterialByMeshRenderer();
}
}

 

相关文章