Skip to content

Instantly share code, notes, and snippets.

@pema99
Last active May 14, 2023 22:27
Show Gist options
  • Save pema99/cb17ac8888a20117aa48e8cc4f9237c4 to your computer and use it in GitHub Desktop.
Save pema99/cb17ac8888a20117aa48e8cc4f9237c4 to your computer and use it in GitHub Desktop.
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