Hi, I’m working on a mobile game. I need resizeable rings (not stroke size but radius). I’ve written a shader works great but shows poor performance on mobile phones.
I set shader’s float array(RadiusArray) from outside once in a while to add more circles. However whenever I add new circle, it gets slower and slower until I remove all circles from the array. Array has two information about a circle: Radius and Opacity.
Is there any way that I don’t have to use for-loop like matrix multiplication etc.? Or any tips for optimization?
Thank you.
Here is how it looks;
Shader "Custom/CircleShader" {
Properties{
_Color("Color", Color) = (1,1,0,0)
_Thickness("Thickness", Range(0.0,0.5)) = 0.05
_Radius("Radius", Range(0.0, 0.5)) = 0.4
}
SubShader{
//Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" }
Pass{
Blend SrcAlpha OneMinusSrcAlpha // Alpha blending
//Cull Off
//Lighting Off
//ZWrite Off //Make On for background
//Fog{ Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color; // low precision type is usually enough for colors
fixed _Thickness;
fixed _Radius;
fixed RadiusArray[80]; //Coming from outside
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct fragmentInput {
fixed4 pos : POSITION;
fixed2 uv : TEXCOORD0;
};
fragmentInput vert(appdata_t v)
{
fragmentInput o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy - fixed2(0.5,0.5);
return o;
}
// r = radius
// d = distance
// t = thickness
fixed antialias(fixed d, fixed t) {
fixed innerRadius = 0;
fixed outerRadius = 0;
fixed totalPixelOpacity = 0;
fixed circleOpacity = 0.0;
fixed currentcircleOpacity = 0.0;
fixed radius;
int circleCount = (int)RadiusArray[0];
for (int ri = circleCount * 2; ri > 0; ri -= 2)
{
radius = RadiusArray[ri - 1];
if (radius < 0 || totalPixelOpacity >= 1) //Last item
break;
innerRadius = radius - 0.5*t;
outerRadius = radius + 0.5*t;
circleOpacity = RadiusArray[ri];
currentcircleOpacity =
1 - (1 - (smoothstep(innerRadius - 0.003,
innerRadius,
d))
+ (smoothstep(outerRadius,
outerRadius + 0.003,
d)));
currentcircleOpacity *= circleOpacity;
totalPixelOpacity += currentcircleOpacity;
}
return totalPixelOpacity > 1 ? 1 : totalPixelOpacity;
}
fixed4 frag(fragmentInput i) : SV_Target{
fixed distance = 0;
distance = length(fixed2(i.uv.x, i.uv.y));
return fixed4(_Color.r, _Color.g, _Color.b, _Color.a*antialias(distance, _Thickness));
}
ENDCG
}
}
}