Shader+UGUI仿制Unity拾色器
先上視頻
使用Shader+UGUI仿制Unity環形拾色器
由于視頻有點小,下面放個大圖
原理介紹
- Shader 著色
組件共使用了3個自定義Shader,對應了拾色器的不同組成部分,分別是:
- 選色調的色環Shader
其實很簡單,首先根據UV圖生成色調圖,然后用一個環來lerp一下,然后在目標位置生成一個小圈圈,
如上圖所示,暴露很多引數供C#調整,有背景顏色、大圈圈大小、小圈圈的偏移、大小粗細等等,其中最重要的是Hue,這是就是色調了,,當我們選取了環上的顏色時,就要動態去設定該值,這樣shader就能在正確的位置生成小圈圈,關鍵的代碼如下:
float3 frag(v2f i) : SV_Target
{
float2 uv = i.uv.xy;
float2 toCenter = float2(0.5, 0.5) - uv;
float angle = atan2(toCenter.y, toCenter.x);
float radius = length(toCenter) * 2;
float3 col = hsb2rgb(float3((angle / UNITY_TWO_PI) + 0.5, radius, 1.0));
float ring = step(_RingInner, radius);
ring = ring * ( 1 - step(_RingOuter, radius));
col = lerp(_BackgroundColor,col, ring);
float ang = -_Hue * UNITY_TWO_PI - UNITY_PI * 0.5;
float2 pos = _PickerRingOffet * (float2(sin(ang), cos(ang)));
float huering = _PickerRingThink / abs(length(toCenter - pos) - _PickerRingSize);
col = lerp(col, float3(0, 0, 0), step(0.5, huering) * ring );
return col;
}
- 選具體顏色的矩形Shader
矩形shader更簡單了,直接用uv來生成矩形的色圖,

最重要的引數是TargetPos,xy分量用來表示小圈圈的位置,z分量用來表示色調(意義同環形shader),
矩形的shader非常簡單,5行代碼搞定(不算return,,):
float3 frag(v2f i) : SV_Target
{
float3 col = hsb2rgb(float3(_TargetPos.z, i.uv.x, i.uv.y));
float2 st = i.uv.xy * 2.0 - 1.0;
float rmpring = _PickerRingThink / abs(length(st - _TargetPos.xy) - _PickerRingSize);
float3 rmprc = lerp(float3(0,0,0), float3(0.5,0.5,0.5), step( 1, rmpring));
col += rmprc;
return col;
}
- 選RGBA分量的Slider的Shader
當我們在環里選了色調,或者在矩形里選了具體的顏色,那么RGB每個分量的顏色都會有變化,表示在當前顏色下,如果改變各自的分量,將得到什么顏色,

這里保留兩個引數,一個是當前的顏色,另一個表示所屬的分量,比如(1,0,0)表示紅色,(0,1,0)表示綠色,(0,0,1)表示藍色,w分量沒有用到,
代碼就更簡單了(4行):
float3 frag(v2f i) : SV_Target
{
float3 col;
col.r = lerp( _CurrColor.r, i.uv.x, _TargetColor.x );
col.g = lerp( _CurrColor.g, i.uv.x, _TargetColor.y );
col.b = lerp( _CurrColor.b, i.uv.x, _TargetColor.z );
return col;
}
- C#代碼
先用UGUI擺好拾色器,做成預制體:

然后寫封裝一下代碼:

基本上就是各種組件的拖動而已,
封裝好之后,可以通過OnColorChanged事件來獲得當顏色被改變時的通知,也可以使用ColorValue變數來直接獲取顏色,當然,也可以通過對這個變數的賦值,來讓拾色器各個控制元件進行相應的更新,比如對這個變數賦值紅色,那么環形拾色器、矩形拾色器還有各個分量的slider都會自動進行計算更新到紅色的指示,
實際上C#代碼沒什么高深復雜的邏輯,只不過就是對這種控制元件的OnValueChanged事件進行監聽,然后將各自的變化更新組件,
最核心的代碼也許只有這些,感覺其余的都沒啥必要貼,,太簡單了,,
private void UpdateValueToUI( UpdateMode mode )
{
prevImage.color = m_theColor;
if ((mode & UpdateMode.UPDATE_PICKER) != 0)
{
rectPicker.SetColor(m_theColor, false);
ringPicker.SetHue(rectPicker.Hue, false);
}
if ((mode & UpdateMode.UPDATE_SLIDER) != 0)
{
redSlider.SetValueWithoutNotify(m_theColor.r);
greenSlider.SetValueWithoutNotify(m_theColor.g);
blueSlider.SetValueWithoutNotify(m_theColor.b);
alphaSlider.SetValueWithoutNotify(m_theColor.a);
}
redLineImage.material.SetColor(currColorId, m_theColor);
greenLineImage.material.SetColor(currColorId, m_theColor);
blueLineImage.material.SetColor(currColorId, m_theColor);
alphaLineImage.color = m_theColor;
if ((mode & UpdateMode.UPDATE_TEXT) != 0)
{
redInput.SetTextWithoutNotify(Mathf.RoundToInt(m_theColor.r * 255f).ToString("0"));
greenInput.SetTextWithoutNotify(Mathf.RoundToInt(m_theColor.g * 255f).ToString("0"));
blueInput.SetTextWithoutNotify(Mathf.RoundToInt(m_theColor.b * 255f).ToString("0"));
alphaInput.SetTextWithoutNotify(Mathf.RoundToInt(m_theColor.a * 255f).ToString("0"));
}
if(( mode & UpdateMode.UPDATE_VALTXT ) != 0 )
colorText.SetTextWithoutNotify(ColorUtility.ToHtmlStringRGB(m_theColor));
}
工程下載鏈接
https://download.csdn.net/download/sdhexu/20463995
或猛擊此處下載
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290526.html
標籤:其他
