Last active
May 14, 2023 22:27
-
-
Save pema99/cb17ac8888a20117aa48e8cc4f9237c4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Unlit/AudioLinkUI" | |
{ | |
Properties | |
{ | |
} | |
SubShader | |
{ | |
Pass | |
{ | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
struct v2f | |
{ | |
float2 uv : TEXCOORD0; | |
float4 vertex : SV_POSITION; | |
}; | |
v2f vert (appdata v) | |
{ | |
v2f o; | |
o.vertex = UnityObjectToClipPos(v.vertex); | |
o.uv = v.uv; | |
return o; | |
} | |
// Colors | |
const static float3 BACKGROUND_COLOR = 0.033; | |
const static float3 FOREGROUND_COLOR = 0.075; | |
const static float3 INACTIVE_COLOR = 0.13; | |
const static float3 ACTIVE_COLOR = 0.45; | |
const static float3 BASS_COLOR_BG = pow(float3(44.0/255.0, 12.0/255.0, 43.0/255.0), 2.2); | |
const static float3 BASS_COLOR_MG = pow(float3(103.0/255.0, 27.0/255.0, 100.0/255.0), 2.2); | |
const static float3 BASS_COLOR_FG = pow(float3(147.0/255.0, 39.0/255.0, 143.0/255.0), 2.2); | |
const static float3 LOWMID_COLOR_BG = pow(float3(76.0/255.0, 53.0/255.0, 18.0/255.0), 2.2); | |
const static float3 HIGHMID_COLOR_BG = pow(float3(42.0/255.0, 60.0/255.0, 19.0/255.0), 2.2); | |
const static float3 HIGH_COLOR_BG = pow(float3(12.0/255.0, 52.0/255.0, 68.0/255.0), 2.2); | |
const static float3 HIGH_COLOR_FG = pow(float3(41.0/255.0, 171.0/255.0, 226.0/255.0), 2.2); | |
// Spacing | |
const static float CORNER_RADIUS = 0.03; | |
const static float FRAME_MARGIN = 0.07; | |
const static float AA_FACTOR = 0.002; | |
const static float HANDLE_RADIUS = 0.007; | |
const static float OUTLINE_WIDTH = 0.002; | |
#define remap(value, low1, high1, low2, high2) ((low2) + ((value) - (low1)) * ((high2) - (low2)) / ((high1) - (low1))) | |
float2x2 rotationMatrix(float angle) | |
{ | |
return float2x2( | |
float2(cos(angle), -sin(angle)), | |
float2(sin(angle), cos(angle)) | |
); | |
} | |
float2 translate(float2 p, float2 offset) | |
{ | |
return p - offset; | |
} | |
float2 rotate(float2 p, float angle) | |
{ | |
return mul(rotationMatrix(angle), p); | |
} | |
float shell(float d, float thickness) | |
{ | |
return abs(d) - thickness; | |
} | |
float inflate(float d, float thickness) | |
{ | |
return d - thickness; | |
} | |
void addElement(inout float3 existing, float3 elementColor, float elementDist) | |
{ | |
existing = lerp(elementColor, existing, smoothstep(0, AA_FACTOR, elementDist)); | |
} | |
float sdRoundedBoxCentered(float2 p, float2 b, float4 r) | |
{ | |
r.xy = (p.x>0.0)?r.xy : r.zw; | |
r.x = (p.y>0.0)?r.x : r.y; | |
float2 q = abs(p)-b*0.5+r.x; | |
return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x; | |
} | |
float sdRoundedBoxTopLeft(float2 p, float2 b, float4 r) | |
{ | |
return sdRoundedBoxCentered(translate(p, b*0.5), b, r); | |
} | |
float sdRoundedBoxBottomRight(float2 p, float2 b, float4 r) | |
{ | |
return sdRoundedBoxCentered(translate(p, float2(b.x,-b.y)*0.5), b, r); | |
} | |
float sdSphere(float2 p, float r) | |
{ | |
return length(p) - r; | |
} | |
float sdTriangleIsosceles(float2 p, float2 q) | |
{ | |
p.x = abs(p.x); | |
float2 a = p - q*clamp( dot(p,q)/dot(q,q), 0.0, 1.0 ); | |
float2 b = p - q*float2( clamp( p.x/q.x, 0.0, 1.0 ), 1.0 ); | |
float s = -sign( q.y ); | |
float2 d = min( float2( dot(a,a), s*(p.x*q.y-p.y*q.x) ), | |
float2( dot(b,b), s*(p.y-q.y) )); | |
return -sqrt(d.x)*sign(d.y); | |
} | |
float sdSegment(float2 p, float2 a, float2 b) | |
{ | |
float2 pa = p-a, ba = b-a; | |
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); | |
return length( pa - ba*h ); | |
} | |
float3 drawTopArea(float2 uv) | |
{ | |
float3 color = FOREGROUND_COLOR; | |
float areaWidth = 1.0 - FRAME_MARGIN * 2; | |
float areaHeight = 0.35; | |
float boxWidth = areaWidth / 4.0; | |
for (uint i = 0; i < 4; i++) | |
{ | |
float boxHeight = 0.25 + sin(_Time.y * 2.0 + float(i) * 0.5) * 0.1; | |
float leftCornerRadius = i == 0 ? CORNER_RADIUS : 0.0; | |
float rightCornerRadius = i == 3 ? CORNER_RADIUS : 0.0; | |
float boxDist = sdRoundedBoxBottomRight( | |
translate(uv, float2(boxWidth * i, areaHeight)), | |
float2(boxWidth, boxHeight), | |
float4(rightCornerRadius, CORNER_RADIUS, leftCornerRadius, CORNER_RADIUS) | |
); | |
float shellDist = shell(boxDist, OUTLINE_WIDTH); | |
// outer shell | |
addElement(color, ACTIVE_COLOR, shellDist); | |
// colored inner portion | |
float3 innerColor = float4x4( | |
float4(BASS_COLOR_BG, 0.0), | |
float4(LOWMID_COLOR_BG, 0.0), | |
float4(HIGHMID_COLOR_BG, 0.0), | |
float4(HIGH_COLOR_BG, 0.0) | |
)[i % 4]; | |
float funcY = remap(sin(uv.x * 20 + _Time.y*5)*sin(uv.x+_Time.y), -1, 1, 0.2, 0.3); | |
float dist = smoothstep(0.003+AA_FACTOR, 0.003, funcY - uv.y); | |
float distAbs = abs(smoothstep(0.003+AA_FACTOR, 0.003, abs(funcY - uv.y))); | |
innerColor = lerp(innerColor, innerColor * 3, distAbs); | |
innerColor = lerp(innerColor, innerColor * 3, dist); | |
addElement(color, innerColor, boxDist+OUTLINE_WIDTH); | |
// Top pivot | |
float handleDist = sdSphere( | |
translate(uv, float2(boxWidth * 0.5 + boxWidth * i, areaHeight-boxHeight)), | |
HANDLE_RADIUS | |
); | |
addElement(color, 1.0, handleDist); | |
} | |
return color; | |
} | |
float3 drawSlider(float2 uv, float2 size, float3 inactiveColor, float3 activeColor) | |
{ | |
float3 color = FOREGROUND_COLOR; | |
const float sliderOffset = 0.02; | |
// Background fill | |
float maxTriangleWidth = size.x - sliderOffset * 2.0; | |
float bgTriangleDist = inflate(sdTriangleIsosceles( | |
rotate(translate(uv, float2(sliderOffset, size.y * 0.5)), UNITY_PI*0.5), | |
float2(size.y*0.3, maxTriangleWidth) | |
), 0.002); | |
addElement(color, inactiveColor, bgTriangleDist); | |
// Current active area | |
float currentTriangleWidth = maxTriangleWidth * (sin(_Time.y) * 0.5 + 0.5); | |
float currentTriangleDist = max(bgTriangleDist, uv.x - currentTriangleWidth - sliderOffset); | |
addElement(color, activeColor, currentTriangleDist); | |
// Slider handle | |
float handleDist = sdSphere( | |
translate(uv, float2(currentTriangleWidth + sliderOffset, size.y * 0.5)), | |
HANDLE_RADIUS | |
); | |
addElement(color, ACTIVE_COLOR, handleDist); | |
// Slider vertical grip | |
float gripDist = abs(uv.x - currentTriangleWidth - sliderOffset) - OUTLINE_WIDTH; | |
addElement(color, ACTIVE_COLOR, gripDist); | |
return color; | |
} | |
float3 drawEqArea(float2 uv, float2 size) | |
{ | |
float3 color = FOREGROUND_COLOR; | |
float2 normUV = uv / size; | |
float y = remap(sin(normUV.x * 20 + _Time.y*5)*sin(normUV.x+_Time.y), -1, 1, 0.2, 0.8); | |
float d = abs(smoothstep(0.03+AA_FACTOR, 0.03, abs(y - normUV.y))); | |
float3 horizontalColor = lerp(BASS_COLOR_FG, HIGH_COLOR_FG, normUV.x); | |
color = lerp(color, horizontalColor, d); | |
return color; | |
} | |
float3 drawUI(float2 uv) | |
{ | |
float3 color = BACKGROUND_COLOR; | |
// Top area | |
float2 topAreaOrigin = translate(uv, FRAME_MARGIN); | |
float2 topAreaSize = float2(1.0 - FRAME_MARGIN * 2, 0.35); | |
float topAreaDist = sdRoundedBoxTopLeft(topAreaOrigin, topAreaSize, CORNER_RADIUS); | |
addElement(color, drawTopArea(topAreaOrigin), topAreaDist); | |
const float sliderMargin = 0.03; | |
const float smallSliderWidth = 0.3; | |
const float sliderHeight = smallSliderWidth * 0.5 - sliderMargin * 0.5; | |
// Gain slider | |
float2 gainSliderOrigin = translate(uv, FRAME_MARGIN + float2(0, 0.4)); | |
float2 gainSliderSize = float2(smallSliderWidth * 2 + sliderMargin, sliderHeight); | |
float gainSliderDist = sdRoundedBoxTopLeft(gainSliderOrigin, gainSliderSize, CORNER_RADIUS); | |
addElement(color, drawSlider(gainSliderOrigin, gainSliderSize, INACTIVE_COLOR, ACTIVE_COLOR), gainSliderDist); | |
// Treble slider | |
float2 trebleSliderOrigin = translate(uv, FRAME_MARGIN + float2(smallSliderWidth+sliderMargin, 0.4+sliderHeight+sliderMargin)); | |
float2 trebleSliderSize = float2(smallSliderWidth, sliderHeight); | |
float trebleSliderDist = sdRoundedBoxTopLeft(trebleSliderOrigin, trebleSliderSize, CORNER_RADIUS); | |
addElement(color, drawSlider(trebleSliderOrigin, trebleSliderSize, HIGH_COLOR_BG, HIGH_COLOR_FG), trebleSliderDist); | |
// Bass slider | |
float2 bassSliderOrigin = translate(uv, FRAME_MARGIN + float2(smallSliderWidth+sliderMargin, 0.4+(sliderHeight+sliderMargin)*2)); | |
float2 bassSliderSize = float2(smallSliderWidth, sliderHeight); | |
float bassSliderDist = sdRoundedBoxTopLeft(bassSliderOrigin, bassSliderSize, CORNER_RADIUS); | |
addElement(color, drawSlider(bassSliderOrigin, bassSliderSize, BASS_COLOR_BG, BASS_COLOR_FG), bassSliderDist); | |
// EQ area | |
float2 eqAreaOrigin = translate(uv, FRAME_MARGIN + float2(0, 0.4+sliderHeight+sliderMargin)); | |
float2 eqAreaSize = float2(smallSliderWidth, smallSliderWidth); | |
float eqAreaDist = sdRoundedBoxTopLeft(eqAreaOrigin, eqAreaSize, CORNER_RADIUS); | |
addElement(color, drawEqArea(eqAreaOrigin, eqAreaSize), eqAreaDist); | |
return color; | |
} | |
float4 frag (v2f i) : SV_Target | |
{ | |
float2 uv = float2(i.uv.x, 1.0 - i.uv.y); | |
uv.y *= 0.3078314 / 0.1856243; // aspect ratio | |
if (uv.x < 0) discard; | |
return float4(drawUI(uv), 1); | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment