Shader HSBC

Shader HSBC

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

參考文件 :

http://wiki.unity3d.com/index.php?title=Shader_Code

http://www.graficaobscura.com/matrix/

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

*

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料