//转自omuying
变灰:
Shader "Custom/GreyShader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); c = float4(Luminance(c)); //设置灰度值 o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }LightShader.shader(外发光效果):
Shader "Custom/LightShader" { Properties { _RimColor ("Rim Color", Color) = (1,1,1,0.5) _InnerColor ("Inner Color", Color) = (1,1,1,0.5) _InnerColorPower ("Inner Color Power", Range(0.0,1.0)) = 0.5 _RimPower ("Rim Power", Range(0.0,5.0)) = 2.5 _AlphaPower ("Alpha Rim Power", Range(0.0,8.0)) = 4.0 _AllPower ("All Power", Range(0.0, 10.0)) = 1.0 } SubShader { Tags { "Queue" = "Transparent" } CGPROGRAM #pragma surface surf Lambert alpha struct Input { float3 viewDir; INTERNAL_DATA }; float4 _RimColor; float _RimPower; float _AlphaPower; float _AlphaMin; float _InnerColorPower; float _AllPower; float4 _InnerColor; void surf (Input IN, inout SurfaceOutput o) { half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal)); o.Emission = _RimColor.rgb * pow (rim, _RimPower)*_AllPower+(_InnerColor.rgb*2*_InnerColorPower); o.Alpha = (pow (rim, _AlphaPower))*_AllPower; } ENDCG } Fallback "VertexLit" }
核心代码是half rim = 1.0 - saturate(dot (normalize(IN.viewDir),o.Normal));
//saturate:returns 0 if x is less than 0; returns 1 if x is greater than 1; returns x otherwise
//saturate for float scalars could be implemented like this
//float saturate(float x){
//return max(0,min(1,x));
//}
//视线方向与法向量夹角为90度时,正好用来模拟侧光的强度
o.Emission=_RimColor.rgb*pow(rim,_RimPower);
//将rim值用一个pow函数进行放大,强化边缘发亮的效果
LightShader1.shader(外发光效果):
Shader "Custom/LightShader1" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Color ("Main Color", Color) = (1,1,1,1) _RimColor ("Rim Color", Color) = (1, 1, 1, 1) _RimWidth ("Rim Width", Float) = 0.7 } SubShader { Pass { Lighting Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; fixed3 color : COLOR; }; uniform float4 _MainTex_ST; uniform fixed4 _RimColor; float _RimWidth; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); float3 viewDir = normalize(ObjSpaceViewDir(v.vertex)); float dotProduct = 1 - dot(v.normal, viewDir); o.color = smoothstep(1 - _RimWidth, 1.0, dotProduct); o.color *= _RimColor; o.uv = v.texcoord.xy; return o; } uniform sampler2D _MainTex; uniform fixed4 _Color; fixed4 frag(v2f i) : COLOR { fixed4 texcol = tex2D(_MainTex, i.uv); texcol *= _Color; texcol.rgb += i.color; return texcol; } ENDCG } } }OutlineShader.shader(边缘发光效果):
Shader "Custom/OutlineShader" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _OutlineColor ("Outline Color", Color) = (1,1,1,1) _Outline ("Outline width", Range (0.0, 0.03)) = .005 _MainTex ("Base (RGB)", 2D) = "white" { } } CGINCLUDE #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; float4 color : COLOR; }; uniform float _Outline; uniform float4 _OutlineColor; v2f vert(appdata v) { // just make a copy of incoming vertex data but scaled according to normal direction v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal); float2 offset = TransformViewToProjection(norm.xy); o.pos.xy += offset * o.pos.z * _Outline; o.color = _OutlineColor; return o; } ENDCG SubShader { Tags { "Queue" = "Transparent" } // note that a vertex shader is specified here but its using the one above Pass { Name "OUTLINE" Tags { "LightMode" = "Always" } Cull Off ZWrite Off ZTest Always ColorMask RGB // alpha not used // you can choose what kind of blending mode you want for the outline Blend SrcAlpha OneMinusSrcAlpha // Normal //Blend One One // Additive //Blend One OneMinusDstColor // Soft Additive //Blend DstColor Zero // Multiplicative //Blend DstColor SrcColor // 2x Multiplicative CGPROGRAM #pragma vertex vert #pragma fragment frag half4 frag(v2f i) :COLOR { return i.color; } ENDCG } Pass { Name "BASE" ZWrite On ZTest LEqual Blend SrcAlpha OneMinusSrcAlpha Material { Diffuse [_Color] Ambient [_Color] } Lighting On SetTexture [_MainTex] { ConstantColor [_Color] Combine texture * constant } SetTexture [_MainTex] { Combine previous * primary DOUBLE } } } SubShader { Tags { "Queue" = "Transparent" } Pass { Name "OUTLINE" Tags { "LightMode" = "Always" } Cull Front ZWrite Off ZTest Always ColorMask RGB // you can choose what kind of blending mode you want for the outline Blend SrcAlpha OneMinusSrcAlpha // Normal //Blend One One // Additive //Blend One OneMinusDstColor // Soft Additive //Blend DstColor Zero // Multiplicative //Blend DstColor SrcColor // 2x Multiplicative CGPROGRAM #pragma vertex vert #pragma exclude_renderers gles xbox360 ps3 ENDCG SetTexture [_MainTex] { combine primary } } Pass { Name "BASE" ZWrite On ZTest LEqual Blend SrcAlpha OneMinusSrcAlpha Material { Diffuse [_Color] Ambient [_Color] } Lighting On SetTexture [_MainTex] { ConstantColor [_Color] Combine texture * constant } SetTexture [_MainTex] { Combine previous * primary DOUBLE } } } Fallback "Diffuse" }OutlineShader1.shader(边缘发光效果):
Shader "Custom/OutlineShader1" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _OutlineColor ("Outline Color", Color) = (1,1,1,1) _Outline ("Outline width", Range (0.0, 0.03)) = .005 _MainTex ("Base (RGB)", 2D) = "white" { } _BumpMap ("Bumpmap", 2D) = "bump" {} } CGINCLUDE #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; float4 color : COLOR; }; uniform float _Outline; uniform float4 _OutlineColor; v2f vert(appdata v) { // just make a copy of incoming vertex data but scaled according to normal direction v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal); float2 offset = TransformViewToProjection(norm.xy); o.pos.xy += offset * o.pos.z * _Outline; o.color = _OutlineColor; return o; } ENDCG SubShader { Tags { "Queue" = "Transparent" } // note that a vertex shader is specified here but its using the one above Pass { Name "OUTLINE" Tags { "LightMode" = "Always" } Cull Off ZWrite Off ZTest Always // you can choose what kind of blending mode you want for the outline Blend SrcAlpha OneMinusSrcAlpha // Normal //Blend One One // Additive //Blend One OneMinusDstColor // Soft Additive //Blend DstColor Zero // Multiplicative //Blend DstColor SrcColor // 2x Multiplicative CGPROGRAM #pragma vertex vert #pragma fragment frag half4 frag(v2f i) : COLOR { return i.color; } ENDCG } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; float2 uv_BumpMap; }; sampler2D _MainTex; sampler2D _BumpMap; uniform float3 _Color; void surf(Input IN, inout SurfaceOutput o) { o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); } ENDCG } SubShader { Tags { "Queue" = "Transparent" } Pass { Name "OUTLINE" Tags { "LightMode" = "Always" } Cull Front ZWrite Off ZTest Always Offset 15,15 // you can choose what kind of blending mode you want for the outline Blend SrcAlpha OneMinusSrcAlpha // Normal //Blend One One // Additive //Blend One OneMinusDstColor // Soft Additive //Blend DstColor Zero // Multiplicative //Blend DstColor SrcColor // 2x Multiplicative CGPROGRAM #pragma vertex vert #pragma exclude_renderers gles xbox360 ps3 ENDCG SetTexture [_MainTex] { combine primary } } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; float2 uv_BumpMap; }; sampler2D _MainTex; sampler2D _BumpMap; uniform float3 _Color; void surf(Input IN, inout SurfaceOutput o) { o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); } ENDCG } Fallback "Outlined/Silhouetted Diffuse" }OutlineShader2.shader(边缘发光效果):
Shader "Custom/OutlineShader2" { Properties { _OutlineColor ("Outline Color", Color) = (1,1,1,1) _Outline ("Outline width", Range (0.0, 0.03)) = .005 } CGINCLUDE #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; float4 color : COLOR; }; uniform float _Outline; uniform float4 _OutlineColor; v2f vert(appdata v) { // just make a copy of incoming vertex data but scaled according to normal direction v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal); float2 offset = TransformViewToProjection(norm.xy); o.pos.xy += offset * o.pos.z * _Outline; o.color = _OutlineColor; return o; } ENDCG SubShader { Tags { "Queue" = "Transparent" } Pass { Name "BASE" Cull Back Blend Zero One // uncomment this to hide inner details: //Offset -8, -8 SetTexture [_OutlineColor] { ConstantColor (0,0,0,0) Combine constant } } // note that a vertex shader is specified here but its using the one above Pass { Name "OUTLINE" Tags { "LightMode" = "Always" } Cull Front // you can choose what kind of blending mode you want for the outline //Blend SrcAlpha OneMinusSrcAlpha // Normal //Blend One One // Additive Blend One OneMinusDstColor // Soft Additive //Blend DstColor Zero // Multiplicative //Blend DstColor SrcColor // 2x Multiplicative CGPROGRAM #pragma vertex vert #pragma fragment frag half4 frag(v2f i) :COLOR { return i.color; } ENDCG } } Fallback "Diffuse" }然后我把这些着色器封装了一下,取名 MaterialController.cs,主要代码如下:然后我把这些着色器封装了一下,取名 MaterialController.cs,主要代码如下:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class MaterialController { private static string GRAY_SHADER_PATH = "Custom/GreyShader"; private static string GRAY_MATERIAL_NAME = "GreyMaterial"; private static string LIGHT_SHADER_PATH_1 = "Custom/LightShader"; private static string LIGHT_SHADER_PATH_2 = "Custom/LightShader1"; private static string LIGHT_MATERIAL_NAME = "LightMaterial"; private static string OUTLINE_SHADER_PATH_1 = "Custom/OutlineShader"; private static string OUTLINE_SHADER_PATH_2 = "Custom/OutlineShader1"; private static string OUTLINE_SHADER_PATH_3 = "Custom/OutlineShader2"; private static string OUTLINE_MATERIAL_NAME = "OutlineMaterial"; ///然后新建立一个 C# 类,取名 RoleController.cs,主要代码如下:/// 设置灰度材质 /// /// Renderer. /// Hashtable. public static void SetGrayMaterial(Renderer renderer, Hashtable shaderParams = null) { if (renderer == null) return; SetMaterial (renderer, Shader.Find (GRAY_SHADER_PATH), GRAY_MATERIAL_NAME, shaderParams); } ////// 取消设置灰度材质 /// ////// Renderer. public static void CancelSetGrayMaterial(Renderer renderer) { if (renderer == null) return; CancelSetMaterial (renderer, GRAY_MATERIAL_NAME); } /// true if cancel set gray material the specified renderer; otherwise,false ./// 设置发光材质 /// /// Renderer. /// Material index. /// Shader parameters. public static void SetLightMaterial(Renderer renderer, int materialIndex = 1, Hashtable shaderParams = null) { if (renderer == null) return; string shaderName = LIGHT_SHADER_PATH_1; if (materialIndex == 2) shaderName = LIGHT_SHADER_PATH_2; SetMaterial (renderer, Shader.Find (shaderName), LIGHT_MATERIAL_NAME, shaderParams); } ////// 取消设置发光材质 /// ////// Renderer. public static void CancelSetLightMaterial(Renderer renderer) { if (renderer == null) return; CancelSetMaterial (renderer, LIGHT_MATERIAL_NAME); } /// true if cancel set gray material the specified renderer; otherwise,false ./// 设置边缘发光材质 /// /// Renderer. /// Material index. /// Shader parameters. public static void SetOutlineMaterial(Renderer renderer, int materialIndex = 1, Hashtable shaderParams = null) { if (renderer == null) return; string shaderName = OUTLINE_SHADER_PATH_1; if (materialIndex == 2) shaderName = OUTLINE_SHADER_PATH_2; if (materialIndex == 3) shaderName = OUTLINE_SHADER_PATH_3; SetMaterial (renderer, Shader.Find (shaderName), OUTLINE_MATERIAL_NAME, shaderParams); } ////// 取消设置边缘发光材质 /// ////// Renderer. public static void CancelSetOutlineMaterial(Renderer renderer) { if (renderer == null) return; CancelSetMaterial (renderer, OUTLINE_MATERIAL_NAME); } /// true if cancel set gray material the specified renderer; otherwise,false ./// 添加材质 /// /// Renderer. /// Shader. /// Material name. /// Shader parameters. public static void SetMaterial(Renderer renderer, Shader shader, string materialName, Hashtable shaderParams) { if (renderer == null || shader == null || string.IsNullOrEmpty(materialName)) return; if (GetMaterial (renderer, materialName) == null) { Material[] sharedMaterials = renderer.sharedMaterials; int materialLength = sharedMaterials.Length; Material[] materialList = new Material[materialLength * 2]; for (int index = 0; index < materialLength; index ++) { materialList[index] = sharedMaterials[index]; Material material = new Material(shader); material.name = materialName; if(material.HasProperty("_MainTex")) { if(shaderParams != null && shaderParams.ContainsKey("_MainTex")) { material.SetTexture("_MainTex", (Texture)shaderParams["_MainTex"]); }else{ if(sharedMaterials[index].HasProperty("_MainTex")) { Texture mainTexture = sharedMaterials[index].GetTexture("_MainTex"); if(mainTexture != null) material.SetTexture("_MainTex", mainTexture); } } } if(material.HasProperty("_BumpMap")) { if(shaderParams != null && shaderParams.ContainsKey("_BumpMap")) { material.SetTexture("_BumpMap", (Texture)shaderParams["_BumpMap"]); }else{ if(sharedMaterials[index].HasProperty("_BumpMap")) { Texture bumpMap = sharedMaterials[index].GetTexture("_BumpMap"); if(bumpMap != null) material.SetTexture("_BumpMap", bumpMap); } } } if(shaderParams != null) { foreach (DictionaryEntry dictionaryEntry in shaderParams) { if(material.HasProperty(dictionaryEntry.Key.ToString())) { if(dictionaryEntry.Value.GetType() == typeof(float)) { material.SetFloat(dictionaryEntry.Key.ToString(), (float)dictionaryEntry.Value); } else if(dictionaryEntry.Value.GetType() == typeof(Color)) { material.SetColor(dictionaryEntry.Key.ToString(), (Color)dictionaryEntry.Value); } } } } materialList[index + materialLength] = material; } renderer.sharedMaterials = materialList; } } ////// 移除材质 /// ////// Renderer. /// Material name. public static void CancelSetMaterial(Renderer renderer, string materialName) { if (renderer == null || string.IsNullOrEmpty(materialName)) return; if (GetMaterial (renderer, materialName)) { IList true if cancel set material the specified renderer materialName; otherwise,false .sharedMaterials = new List (); foreach(Material material in renderer.sharedMaterials) { if(material.name != materialName) { sharedMaterials.Add(material); } } int materialLength = sharedMaterials.Count; Material[] materialList = new Material[materialLength]; for(int index = 0; index < materialLength; index ++) { materialList[index] = sharedMaterials[index]; } renderer.sharedMaterials = materialList; } } /// /// 获取材质 /// ///The material. /// Renderer. /// Gray material name. private static Material GetMaterial(Renderer renderer, string materialName) { Material[] materialList = renderer.sharedMaterials; if (materialList == null || materialList.Length == 0) return null; foreach (Material material in materialList) { if(material.name == materialName) return material; } return null; } }
using UnityEngine; using System.Collections; public class RoleController : MonoBehaviour { private SkinnedMeshRenderer skinnedMeshRenderer; private bool shiftStatus; void Awake() { skinnedMeshRenderer = this.GetComponentInChildren(); } void Update() { this.shiftStatus = false; if (Input.GetKey (KeyCode.LeftShift)) { this.shiftStatus = true; } if(Input.GetMouseButtonDown(0) && !shiftStatus) { if(this.skinnedMeshRenderer == null) return; // 设置灰度材质 MaterialController.SetGrayMaterial(skinnedMeshRenderer); } if(Input.GetMouseButtonUp(0) && !shiftStatus) { if(this.skinnedMeshRenderer == null) return; // 取消设置灰度材质 MaterialController.CancelSetGrayMaterial(skinnedMeshRenderer); } if (Input.GetMouseButtonDown (1)) { if(this.skinnedMeshRenderer == null) return; // 设置发光材质 Hashtable shaderParams = new Hashtable(); shaderParams.Add("_InnerColor", Color.yellow); shaderParams.Add("_RimColor", Color.yellow); shaderParams.Add("_InnerColorPower", 0.9f); shaderParams.Add("_RimPower", 4f); MaterialController.SetLightMaterial(skinnedMeshRenderer, Random.Range(1, 3), shaderParams); } if (Input.GetMouseButtonUp (1)) { if(this.skinnedMeshRenderer == null) return; // 取消设置发光材质 MaterialController.CancelSetLightMaterial(skinnedMeshRenderer); } if (Input.GetMouseButtonDown (0) && shiftStatus) { if(this.skinnedMeshRenderer == null) return; // 设置边缘材质 MaterialController.SetOutlineMaterial(skinnedMeshRenderer, Random.Range(1, 4)); } if (Input.GetMouseButtonUp (0) && shiftStatus) { if(this.skinnedMeshRenderer == null) return; // 取消设置边缘材质 MaterialController.CancelSetOutlineMaterial(skinnedMeshRenderer); } } }