|
Shader "Custom/SpectrumRemapping" { |
|
Properties { |
|
_MainTex("Texture", 2D) = "white" {} |
|
_Frequencies("Frequencies (log)", Vector) = (0, 1, 0, 1) |
|
} |
|
SubShader { |
|
Pass { |
|
CGPROGRAM |
|
#pragma vertex vertex |
|
#pragma fragment fragment |
|
|
|
#include "UnityCG.cginc" |
|
|
|
struct VertexIn { |
|
float4 position : POSITION; |
|
float2 uvCoord : TEXCOORD0; |
|
}; |
|
|
|
struct FragmentIn |
|
{ |
|
float2 uvCoord : TEXCOORD0; |
|
float4 position : SV_POSITION; |
|
}; |
|
|
|
FragmentIn vertex(VertexIn v) { |
|
FragmentIn o; |
|
o.position = UnityObjectToClipPos(v.position); |
|
o.uvCoord = v.uvCoord; |
|
return o; |
|
} |
|
|
|
static const fixed pi = atan(1) * 4; |
|
static const fixed tau = atan(1) * 8; |
|
static const fixed sqrt3 = sqrt(3); |
|
static const fixed halfSqrt3 = sqrt3 * .5f; |
|
static const fixed fiveSixth = 5.f / 6; |
|
|
|
fixed3 RGB2HSV(fixed3 rgb) { |
|
fixed3 xyz |
|
= rgb.r * fixed3(1, 0, 1) |
|
+ rgb.g * fixed3(-.5f, halfSqrt3, 1) |
|
+ rgb.b * fixed3(-.5f, -halfSqrt3, 1); |
|
fixed h = frac(atan2(xyz.y, xyz.x) / tau + 1); |
|
fixed s = length(xyz.xy); |
|
fixed v = xyz.z / 3; |
|
return fixed3(h, s, v); |
|
} |
|
|
|
// HSV: Hue - Spectrum - Value |
|
// XSV: Relative Frequency - # - # |
|
fixed3 HSV2XSV(fixed3 hsv) { |
|
if(hsv.x > fiveSixth) |
|
hsv.x -= 1; |
|
hsv.x /= fiveSixth; |
|
return hsv; |
|
} |
|
|
|
fixed3 RGB2XSV(fixed3 rgb) { |
|
return HSV2XSV(RGB2HSV(rgb)); |
|
} |
|
|
|
fixed3 XSV2HSV(fixed3 xsv) { |
|
fixed offset = abs(xsv.x - clamp(xsv.x, 0, 1)); |
|
fixed dim = exp(-offset); |
|
fixed3 hsv = fixed3( |
|
clamp(xsv.x, 0, 1) * fiveSixth, |
|
xsv.y, |
|
xsv.z * dim |
|
); |
|
return hsv; |
|
} |
|
|
|
fixed3 HSV2RGB(fixed3 hsv) { |
|
hsv.x *= tau; |
|
fixed3 xyz = fixed3( |
|
fixed2(cos(hsv.x), sin(hsv.x)) * hsv.y, |
|
hsv.z * 3 |
|
); |
|
fixed3 rgb |
|
= xyz.x * fixed3(2, -1, -1) |
|
+ xyz.y * fixed3(0, sqrt3, -sqrt3) |
|
+ xyz.z * fixed3(1, 1, 1); |
|
rgb /= 3; |
|
return rgb; |
|
} |
|
|
|
fixed3 XSV2RGB(fixed3 xsv) { |
|
return HSV2RGB(XSV2HSV(xsv)); |
|
} |
|
|
|
float IntervalTransform(float x, float2 source, float2 spectating) { |
|
x = (source.y - source.x) * x + source.x; |
|
x = (x - spectating.x) / (spectating.y - spectating.x); |
|
return x; |
|
} |
|
|
|
sampler2D _MainTex; |
|
float4 _Frequencies; |
|
|
|
fixed4 fragment(FragmentIn i) : SV_Target{ |
|
fixed4 sample = tex2D(_MainTex, i.uvCoord); |
|
fixed3 xsv = RGB2XSV(sample.rgb); |
|
xsv.x = IntervalTransform(xsv.x, _Frequencies.xy, _Frequencies.zw); |
|
fixed3 _rgb = XSV2RGB(xsv); |
|
return fixed4(_rgb, sample.a); |
|
} |
|
ENDCG |
|
} |
|
} |
|
} |