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