MediaPlayerUI.shader 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // Credit to Inigo Quilez (https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm) for many of the 2D functions used
  2. Shader "Unlit/MediaPlayerUI"
  3. {
  4. Properties
  5. {
  6. [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
  7. _Color("Tint", Color) = (1,1,1,1)
  8. _StencilComp("Stencil Comparison", Float) = 8
  9. _Stencil("Stencil ID", Float) = 0
  10. _StencilOp("Stencil Operation", Float) = 0
  11. _StencilWriteMask("Stencil Write Mask", Float) = 255
  12. _StencilReadMask("Stencil Read Mask", Float) = 255
  13. _ColorMask("Color Mask", Float) = 15
  14. [KeywordEnum(Circle, Play, Pause, PlayPause, Buffering, Volume, Forward, Back, CC, Options, Spectrum)] UI("UI Element", Float) = 0
  15. _Morph("Morph", Range(0, 1)) = 0
  16. _Mute("Mute", Range(0, 1)) = 0
  17. _Volume("Volume", Range(0, 1)) = 1
  18. [Toggle(DRAW_OUTLINE)] _DrawOutline("Draw Outline", Float) = 0
  19. _OutlineSize("Outline Size", Range(0, 0.1)) = 0.05
  20. _OutlineOpacity("Outline Opacity", Range(0, 1)) = 0.25
  21. _OutlineSoftness("Outline Softness", Range(0, 1)) = 0
  22. }
  23. SubShader
  24. {
  25. Tags
  26. {
  27. "Queue"="Transparent"
  28. "IgnoreProjector"="True"
  29. "RenderType"="Transparent"
  30. "PreviewType"="Plane"
  31. "CanUseSpriteAtlas"="True"
  32. }
  33. Stencil
  34. {
  35. Ref[_Stencil]
  36. Comp[_StencilComp]
  37. Pass[_StencilOp]
  38. ReadMask[_StencilReadMask]
  39. WriteMask[_StencilWriteMask]
  40. }
  41. Cull Off
  42. Lighting Off
  43. ZWrite Off
  44. ZTest[unity_GUIZTestMode]
  45. Fog{ Mode Off }
  46. Blend SrcAlpha OneMinusSrcAlpha
  47. ColorMask[_ColorMask]
  48. Pass
  49. {
  50. CGPROGRAM
  51. #pragma vertex vert
  52. #pragma fragment frag
  53. #pragma multi_compile UI_CIRCLE UI_PLAY UI_PAUSE UI_PLAYPAUSE UI_BUFFERING UI_VOLUME UI_FORWARD UI_BACK UI_CC UI_OPTIONS UI_SPECTRUM
  54. #pragma shader_feature DRAW_OUTLINE
  55. #include "UnityCG.cginc"
  56. struct appdata_t
  57. {
  58. float4 vertex : POSITION;
  59. float4 color : COLOR;
  60. float2 texcoord : TEXCOORD0;
  61. };
  62. struct v2f
  63. {
  64. float4 vertex : SV_POSITION;
  65. fixed4 color : COLOR;
  66. half2 uv : TEXCOORD0;
  67. float4 worldPosition : TEXCOORD1;
  68. };
  69. uniform fixed4 _Color;
  70. uniform float _Morph;
  71. uniform float _Volume;
  72. uniform float _Mute;
  73. uniform float _OutlineSize;
  74. uniform float _OutlineOpacity;
  75. uniform float _OutlineSoftness;
  76. #if UI_SPECTRUM
  77. #if SHADER_API_GLES
  78. uniform float _Spectrum[4];
  79. #else
  80. uniform float _Spectrum[128];
  81. #endif
  82. uniform float _SpectrumRange;
  83. uniform float _SpectrumMax;
  84. #endif
  85. sampler2D _MainTex;
  86. float4 _MainTex_ST;
  87. v2f vert(appdata_t IN)
  88. {
  89. v2f OUT;
  90. OUT.worldPosition = IN.vertex;
  91. OUT.vertex = UnityObjectToClipPos(IN.vertex);
  92. #ifdef UNITY_HALF_TEXEL_OFFSET
  93. OUT.vertex.xy += (_ScreenParams.zw - 1.0)*float2(-1, 1);
  94. #endif
  95. OUT.uv.xy = IN.texcoord.xy;
  96. OUT.color = IN.color * _Color;
  97. return OUT;
  98. }
  99. float ndot(float2 a, float2 b) { return a.x*b.x - a.y*b.y; }
  100. float opU(float d1, float d2) { return min(d1, d2); }
  101. float opS(float d1, float d2) { return max(-d1, d2); }
  102. float opI(float d1, float d2) { return max(d1, d2); }
  103. float sdCircle(in float2 p, float r)
  104. {
  105. return length(p) - r;
  106. }
  107. float sdRhombus(in float2 p, in float2 b)
  108. {
  109. float2 q = abs(p);
  110. float h = clamp((-2.0*ndot(q, b) + ndot(b, b)) / dot(b, b), -1.0, 1.0);
  111. float d = length(q - 0.5*b*float2(1.0 - h, 1.0 + h));
  112. return d * sign(q.x*b.y + q.y*b.x - b.x*b.y);
  113. }
  114. float sdEquilateralTriangle(in float2 p)
  115. {
  116. const float k = sqrt(3.0);
  117. p.x = abs(p.x) - 1.0;
  118. p.y = p.y + 1.0 / k;
  119. if (p.x + k*p.y > 0.0) p = float2(p.x - k*p.y, -k*p.x - p.y) / 2.0;
  120. p.x -= clamp(p.x, -2.0, 0.0);
  121. return -length(p)*sign(p.y);
  122. }
  123. float sdTriangle(in float2 p, in float2 p0, in float2 p1, in float2 p2)
  124. {
  125. float2 e0 = p1 - p0, e1 = p2 - p1, e2 = p0 - p2;
  126. float2 v0 = p - p0, v1 = p - p1, v2 = p - p2;
  127. float2 pq0 = v0 - e0*clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);
  128. float2 pq1 = v1 - e1*clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);
  129. float2 pq2 = v2 - e2*clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);
  130. float s = sign(e0.x*e2.y - e0.y*e2.x);
  131. float2 d = min(min(float2(dot(pq0, pq0), s*(v0.x*e0.y - v0.y*e0.x)),
  132. float2(dot(pq1, pq1), s*(v1.x*e1.y - v1.y*e1.x))),
  133. float2(dot(pq2, pq2), s*(v2.x*e2.y - v2.y*e2.x)));
  134. return -sqrt(d.x)*sign(d.y);
  135. }
  136. float sdTriangleIsosceles(in float2 p, in float2 q)
  137. {
  138. p.x = abs(p.x);
  139. float2 a = p - q*clamp(dot(p, q) / dot(q, q), 0.0, 1.0);
  140. float2 b = p - q*float2(clamp(p.x / q.x, 0.0, 1.0), 1.0);
  141. float s = -sign(q.y);
  142. float2 d = min(float2(dot(a, a), s*(p.x*q.y - p.y*q.x)),
  143. float2(dot(b, b), s*(p.y - q.y)));
  144. return -sqrt(d.x)*sign(d.y);
  145. }
  146. float sdBox(in float2 p, in float2 b)
  147. {
  148. float2 d = abs(p) - b;
  149. return length(max(d, float2(0.0, 0.0))) + min(max(d.x, d.y), 0.0);
  150. }
  151. float sdRoundedBox(in float2 p, in float2 b, in float4 r)
  152. {
  153. r.xy = (p.x>0.0)?r.xy : r.zw;
  154. r.x = (p.y>0.0)?r.x : r.y;
  155. float2 q = abs(p)-b+r.x;
  156. return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
  157. }
  158. float sdArc(in float2 p, in float2 sca, in float2 scb, in float ra, float rb)
  159. {
  160. p = mul(float2x2(sca.x,sca.y,-sca.y,sca.x), p);
  161. p.x = abs(p.x);
  162. float k = (scb.y*p.x>scb.x*p.y) ? dot(p.xy,scb) : length(p.xy);
  163. return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;
  164. }
  165. float2 rotate2d(float2 v, float a)
  166. {
  167. float s = sin(a);
  168. float c = cos(a);
  169. float2x2 m = float2x2(c, -s, s, c);
  170. return mul(m,v);
  171. }
  172. #if UI_FORWARD || UI_BACK
  173. float forward(float2 uv)
  174. {
  175. float r1 = 100000.0;
  176. r1 = sdTriangleIsosceles(float2(uv.y, -uv.x) + float2(0.0, 0.333), float2(0.666, 0.666));
  177. r1 = opS(r1, sdTriangleIsosceles(float2(uv.y, -uv.x) + float2(0.0, 0.333 * 1.5), float2(0.666, 0.666)));
  178. uv.x += 0.2;
  179. float r2 = 100000.0;
  180. r2 = sdTriangleIsosceles(float2(uv.y, -uv.x) + float2(0.0, 0.333), float2(0.666, 0.666));
  181. //r2 = opS(r2, sdTriangleIsosceles(float2(uv.y, -uv.x) + float2(0.0, 0.333 * 1.5), float2(0.666, 0.666)));
  182. float r = opU(r1, r2);
  183. return r;
  184. }
  185. #endif
  186. #if UI_VOLUME
  187. float volume(float2 uv)
  188. {
  189. float r = 100000.0;
  190. uv.x += 0.25;
  191. // Cone
  192. r = opU(r, sdBox(uv + float2(0.1, 0.0), float2(0.25, 0.25)));
  193. r = opU(r, sdTriangleIsosceles(float2(uv.y, uv.x) + float2(0.0, 0.3), float2(0.6, 0.6)));
  194. // Ripple occluder
  195. float s = sdBox(uv + float2(0, 0.0), float2(0.4, 0.7));
  196. // Ripple thickness
  197. float rt = 0.15;
  198. // Ripple 1
  199. float offset = -0.25;
  200. if (_Volume > 0.0)
  201. {
  202. float t = saturate(_Volume / 0.5);
  203. r = opU(r, opS(s, sdCircle(uv + float2(offset, 0.0), rt*lerp(1, 2, t))));
  204. }
  205. // Ripple 2
  206. float a;
  207. //a = sdCircle(uv + float2(offset, 0.0), 0.6 - rt * 3);
  208. //a = opS(a, opS(s, sdCircle(uv + float2(offset, 0.0), 0.6 - rt * 2)));
  209. //r = opU(a, r);
  210. // Ripple 3
  211. if (_Volume > 0.5)
  212. {
  213. float t = saturate((_Volume - 0.5) / 0.5);
  214. a = sdCircle(uv + float2(offset, 0.0), (0.6 - rt));
  215. a = opS(a, opS(s, sdCircle(uv + float2(offset, 0.0), lerp(0.6-rt, 0.6, t))));
  216. r = opU(a, r);
  217. }
  218. // Crossout
  219. if (_Mute > 0.0)
  220. {
  221. float maxLength = 0.8;
  222. float length = _Mute * maxLength;
  223. {
  224. // Cutout
  225. r = opS(-r, -sdBox(rotate2d(uv - float2(0.25, 0), -3.14/4) + float2(-0.1, length/1 - maxLength/1), float2(0.1, length*1)));
  226. // Line
  227. r = opU(r, sdBox(rotate2d(uv - float2(0.25, 0), -3.14/4) + float2(0.0, length/1 - maxLength/1), float2(0.1, length*1)));
  228. }
  229. }
  230. return r;
  231. }
  232. #endif
  233. #if UI_CC
  234. float ccbutton(float2 uv)
  235. {
  236. float r = 100000.0;
  237. float barHeight = 0.1;
  238. float boxSize = 0.65;
  239. float r3 = sdRoundedBox(uv, float2(boxSize, boxSize * 0.9), float4(0.25, 0.25, 0.25, 0.25));
  240. float angle1 = 0.0;
  241. float angle2 = 2.3;
  242. float thickeness = 0.08;
  243. float size = 0.25;
  244. float rLeftC = sdArc(float2(0.35 + uv.x*1.5, uv.y), float2(sin(angle1), cos(angle1)), float2(sin(angle2), cos(angle2)), size, thickeness);
  245. float rRightC = sdArc(float2(-0.40 + uv.x*1.5, uv.y), float2(sin(angle1), cos(angle1)), float2(sin(angle2), cos(angle2)), size, thickeness);
  246. r = opU(rLeftC, rRightC);
  247. r = opS(r, r3);
  248. if (_Morph > 0.0)
  249. {
  250. float barWidth = lerp(0.0, boxSize, _Morph);
  251. float r4 = sdBox(uv + float2(0.0, boxSize + barHeight * 2.0), float2(barWidth, barHeight));
  252. r = opU(r, r4);
  253. }
  254. return r;
  255. }
  256. #endif
  257. #if UI_OPTIONS
  258. float optionsgear(float2 uv, float radius, float discRatio, float holeRatio, float spokeRatio)
  259. {
  260. float r = 100000.0;
  261. float r1 = sdCircle(uv, radius * holeRatio);
  262. float r2 = sdCircle(uv, radius * discRatio);
  263. float rotationOffset = lerp(0.0, 3.141592654/6.0, _Morph);
  264. float b1 = sdBox(rotate2d(uv, (3.141592654 / 2.0) + rotationOffset), float2(radius, radius * spokeRatio));
  265. float b2 = sdBox(rotate2d(uv, (3.141592654 / 6.0) + rotationOffset), float2(radius, radius * spokeRatio));
  266. float b3 = sdBox(rotate2d(uv,-(3.141592654 / 6.0) + rotationOffset), float2(radius, radius * spokeRatio));
  267. r = r2; // Base circle
  268. r = opU(r, b1); // Spoke 1
  269. r = opU(r, b2); // Spoke 2
  270. r = opU(r, b3); // Spoke 3
  271. r = opS(r1, r); // Hole
  272. return r;
  273. }
  274. #endif
  275. #if UI_BUFFERING
  276. float CircularDistance(float a, float b, float range)
  277. {
  278. float d1 = abs(a-b);
  279. //float d2 = range - d1;
  280. //return lerp((a-b), d2, d1 / (range/2));
  281. if (d1 > range/2)
  282. {
  283. d1 = (range - d1);
  284. }
  285. else
  286. {
  287. d1 = a-b;
  288. }
  289. return d1;
  290. }
  291. #endif
  292. fixed4 getColorWithOutline(float d, float3 shapeColor, float3 outlineColor)
  293. {
  294. float dw = fwidth(d) * 0.5;
  295. float shapeAlpha = smoothstep(dw, -dw, d);
  296. #if !DRAW_OUTLINE
  297. return float4(shapeColor, shapeAlpha);
  298. #else
  299. float od = (d - _OutlineSize);
  300. float dw2 = fwidth(od) * 0.5;
  301. float outlineAlpha = smoothstep(dw2 + _OutlineSoftness, -dw2 - _OutlineSoftness, od);
  302. return lerp(float4(outlineColor, outlineAlpha * _OutlineOpacity), float4(shapeColor, shapeAlpha), shapeAlpha);
  303. #endif
  304. }
  305. fixed4 frag(v2f i) : SV_Target
  306. {
  307. #if UI_SPECTRUM
  308. // In GLES2.0 indexing from the _Spectrum[] array is not supported
  309. #if SHADER_API_GLES
  310. float v = 0.0;
  311. float d = 0.0;
  312. #else
  313. float x = (pow(i.uv.x, 1.0) * _SpectrumRange)-1.0;
  314. //_Spectrum[0] = 0.0;
  315. // Bilinear sample the values
  316. float scale = (1.0+i.uv.x * 8.0); // Scale higher freqs to give them more movement
  317. float v1 = 0.0;
  318. float v2 = 0.0;
  319. int t1 = floor(x);
  320. int t2 = ceil(x);
  321. if (t1 >= 0)
  322. {
  323. v1 = (_Spectrum[t1] * scale);
  324. }
  325. if (t2 >= 0)
  326. {
  327. v2 = (_Spectrum[t2] * scale);
  328. }
  329. v1 = max(v1, 0.01);
  330. v2 = max(v2, 0.01);
  331. float2 uvn = float2(0.0, i.uv.y);
  332. // Get vertical distance
  333. float d1 = (abs(i.uv.y - 0.5) - (v1/1.0));
  334. float d2 = (abs(i.uv.y - 0.5) - (v2/1.0));
  335. // Interpolate
  336. float xf = frac(x);
  337. float v = saturate(lerp(v1, v2, xf));
  338. float d = lerp(d1, d2, xf);
  339. #endif
  340. // Get colour from texture
  341. float yy2 = abs(i.uv.y - 0.5) * 2.0;
  342. float yy = v;
  343. float level = i.uv.y;// + pow(yy2+v, 8);
  344. float3 col = level;//tex2D(_MainTex, float2(level, 0.0f));
  345. //col.g += abs(i.uv.x);
  346. return getColorWithOutline(d, col, float3(0.0, 0.0, 0.0)) * i.color;
  347. #else
  348. #if UI_CIRCLE
  349. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  350. float d = sdCircle(uvn, 1.0);
  351. #elif UI_PLAY
  352. float2 uvn = (i.uv.xy - float2(0.5, 0.5)) / 0.5;
  353. float d = sdTriangle(uvn, float2(-0.6, 0.6), float2(0.6, 0), float2(-0.6, -0.6));
  354. #elif UI_PAUSE
  355. float d1 = sdBox(i.uv - 0.5 + float2(0.2, 0.0), float2(0.1, 0.3));
  356. float d2 = sdBox(i.uv - 0.5 - float2(0.2, 0.0), float2(0.1, 0.3));
  357. float d = min(d1, d2);
  358. //c = 1.0 - saturate(smoothstep(dw-0.022, -dw, d))*0.2;
  359. #elif UI_PLAYPAUSE
  360. float2 uvn = (i.uv.xy - float2(0.5, 0.5)) / 0.5;
  361. float d3 = sdTriangle(uvn, float2(-0.6, 0.6), float2(0.6, 0), float2(-0.6, -0.6));
  362. float d1 = sdBox(i.uv - 0.5 + float2(0.2, 0.0), float2(0.1, 0.3));
  363. float d2 = sdBox(i.uv - 0.5 - float2(0.2, 0.0), float2(0.1, 0.3));
  364. float d = min(d1, d2);
  365. float dw1 = fwidth(d) * 0.5;
  366. float dw3 = fwidth(d3) * 0.5;
  367. float dw = lerp(dw1, dw3, _Morph);
  368. //a = smoothstep(dw, -dw, lerp(d, d3, _Morph));
  369. d = lerp(d, d3, _Morph);
  370. //c = 1.0 - saturate(smoothstep(-0.025, 0, lerp(d, d3, _Morph)))*0.2;
  371. #elif UI_BUFFERING
  372. float rsize = 0.05;
  373. float r = 0.5;
  374. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  375. // Inner radius
  376. float d = sdCircle(uvn, r - rsize);
  377. // Outer radius
  378. d = opS(d, sdCircle(uvn, r + rsize));
  379. // Animation angle
  380. float za = -(_Time.x * 160) + cos(_Time.y*2.0);
  381. float zz = sin(_Time.y);
  382. // Create point at the animated angle, at the same radius as this UV
  383. float2 dp = float2(sin(za), cos(za)) * length(uvn);
  384. // Calculate angle between the UV and the new point and subtract offset
  385. float dy = abs(atan((dp.x - uvn.x)/(dp.y - uvn.y))) - abs(zz);
  386. d = opI(d, dy);
  387. #elif UI_VOLUME
  388. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  389. float d = volume(uvn);
  390. #elif UI_FORWARD
  391. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  392. float d = forward(uvn);
  393. #elif UI_BACK
  394. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  395. float d = forward(float2(-uvn.x, uvn.y));
  396. #elif UI_CC
  397. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  398. float d = ccbutton(uvn);
  399. #elif UI_OPTIONS
  400. float2 uvn = (i.uv.xy - 0.5) / 0.5;
  401. float d = optionsgear(uvn, 0.75, 0.75, 0.35, 0.25);
  402. #endif
  403. return getColorWithOutline(d, float3(1.0, 1.0, 1.0), float3(0.0, 0.0, 0.0)) * i.color;
  404. #endif
  405. }
  406. ENDCG
  407. }
  408. }
  409. }