參考: 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);
}
}
}
參考文件 :