參考: http://forum.unity3d.com/threads/hue-saturation-brightness-contrast-shader.260649/ 的文章
另外重寫一個可動態修改的 shader.
修改後的代碼
Shader "Unlit/Texture HSBC" { Properties { _MainTex("Base (RGB), Alpha (A)", 2D) = "black" {} _Hue("Hue", Range(0, 1.0)) = 0 _Saturation("Saturation", Range(0, 1.0)) = 0.5 _Brightness("Brightness", Range(0, 1.0)) = 0.5 _Contrast("Contrast", Range(0, 1.0)) = 0.5 } SubShader { LOD 100 Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Cull Off Lighting Off ZWrite On Fog{ Mode Off } Offset -1, -1 Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" // Function inline float3 applyHue(float3 aColor, float aHue) { float angle = radians(aHue); float3 k = float3(0.57735, 0.57735, 0.57735); float cosAngle = cos(angle); //Rodrigues' rotation formula return aColor * cosAngle + cross(k, aColor) * sin(angle) + k * dot(k, aColor) * (1 - cosAngle); } inline float4 applyHSBEffect(float4 startColor, fixed4 hsbc) { float hue = 360 * hsbc.r; float saturation = hsbc.g * 2; float brightness = hsbc.b * 2 - 1; float contrast = hsbc.a * 2; float4 outputColor = startColor; outputColor.rgb = applyHue(outputColor.rgb, hue); outputColor.rgb = (outputColor.rgb - 0.5f) * contrast + 0.5f + brightness; outputColor.rgb = lerp(Luminance(outputColor.rgb), outputColor.rgb, saturation); return outputColor; } struct appdata_t { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; fixed4 color : COLOR; }; struct v2f { float4 vertex : SV_POSITION; half2 texcoord : TEXCOORD0; fixed4 hsbc : COLOR; }; sampler2D _MainTex; fixed _Hue, _Saturation, _Brightness, _Contrast; v2f vert(appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.texcoord = v.texcoord; o.hsbc = fixed4(_Hue, _Saturation, _Brightness, _Contrast); return o; } fixed4 frag(v2f i) : COLOR { float4 startColor = tex2D(_MainTex, i.texcoord); float4 hsbColor = applyHSBEffect(startColor, i.hsbc); return hsbColor; } ENDCG } // Pass } // SubShader SubShader { LOD 100 Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Pass { Cull Off Lighting Off ZWrite Off Fog{ Mode Off } Offset -1, -1 ColorMask RGB //AlphaTest Greater .01 Blend SrcAlpha OneMinusSrcAlpha ColorMaterial AmbientAndDiffuse SetTexture[_MainTex] { Combine Texture * Primary } } // Pass } // SubShader }
接著在 Unity3D 因為項目要求需要到同時修改一系列的 shader HSBC, 所以分別建立以下的組件:
struct HSBC : IEquatable<HSBC> { public float Hue, Saturation, Brightness, Contrast; public HSBC(float hue, float saturation, float brightness, float contrast) { Hue = hue; Saturation = saturation; Brightness = brightness; Contrast = contrast; } public bool Equals(HSBC other) { return Mathf.Approximately(Hue, other.Hue) && Mathf.Approximately(Saturation, other.Saturation) && Mathf.Approximately(Brightness, other.Brightness) && Mathf.Approximately(Contrast, other.Contrast); } public void LerpTo(HSBC target, float t) { Hue = LerpNear(Hue, target.Hue, t); Saturation = LerpNear(Saturation, target.Saturation, t); Brightness = LerpNear(Brightness, target.Brightness, t); Contrast = LerpNear(Contrast, target.Contrast, t); } private float LerpNear(float current, float target, float t) { return (Mathf.Approximately(current, target)) ? target : Mathf.Lerp(current, target, t); } }
然後實際使用的元件面版.
using UnityEngine; using System.Collections.Generic; using System.Linq; public class CWorldMapColorHandler : CSingleton<CWorldMapColorHandler> { public Shader m_TargetShader; public List<Material> m_MaterialList = new List<Material>(); [Range(0f,1f)] public float m_Hue = 0f, m_Saturation = 0.5f, m_Brightness = 0.5f, m_Contrast = 0.5f; HSBC m_Last; HSBC m_Current { get { return new HSBC(m_Hue, m_Saturation, m_Brightness, m_Contrast); } } [ContextMenu("Register Child Renderer")] void OnValidate() { // Ensure all related material reference in the list. List<MeshRenderer> renders = GetComponentsInChildren<MeshRenderer>().ToList(); foreach (MeshRenderer render in renders) { for (int i = 0; i < render.sharedMaterials.Length; i++) { if (render.sharedMaterials[i] == null || render.sharedMaterials[i].shader.GetInstanceID() != m_TargetShader.GetInstanceID()) continue; if (!m_MaterialList.Any(o => o.GetHashCode() == render.sharedMaterials[i].GetHashCode())) m_MaterialList.Add(render.sharedMaterials[i]); } } } new void Awake() { base.Awake(); m_Last = new HSBC(m_Hue, m_Saturation, m_Brightness, m_Contrast); } void Update() { if(!m_Current.Equals(m_Last)) { m_Last.LerpTo(m_Current, Time.deltaTime); // direct change Material values, 3 loops, change sharedMaterials 237 loops foreach(Material mat in m_MaterialList) { mat.SetFloat("_Hue", m_Last.Hue); mat.SetFloat("_Saturation", m_Last.Saturation); mat.SetFloat("_Brightness", m_Last.Brightness); mat.SetFloat("_Contrast", m_Last.Contrast); } } } new void OnDestroy() { base.OnDestroy(); // reset material color. foreach (Material mat in m_MaterialList) { mat.SetFloat("_Hue", 0f); mat.SetFloat("_Saturation", .5f); mat.SetFloat("_Brightness", .5f); mat.SetFloat("_Contrast", .5f); } } }
參考文件 :