zoukankan      html  css  js  c++  java
  • unity中动态处理模型透明或材质的方法

    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();
    }
    }

  • 相关阅读:
    Weex框架源码分析(Android)(一)
    Android之手机振动和振铃
    使用selenium实现模拟淘宝登陆
    Android—修改button属性
    一个ROS的服务,使机器人向前移动指定距离
    用python写一个百度翻译
    python的特殊数字类型(无穷大、无穷小等)
    ESP32 开发笔记(十二)LittlevGL 添加自定义字体和物理按键
    设计的不错的网站
    轻功到底有没有?
  • 原文地址:https://www.cnblogs.com/nanyang0310/p/14216324.html
Copyright © 2011-2022 走看看