I have a pixel shader that draws a nice anti aliased circle that works great on PC, but I’m having some problems on Android. I don’t understand what is happening and I hope someone here might be able to figure it out.
I have not had the opportunity to test this on a different device, so I don’t know if this is a general Android issue or something specific to my phone.
At first it appears to work as intended
But if the radius is larger than 256 it draws a square instead
If the radius is between 256 and 257 all the pixels outside the circle are semi-transparent, like the pixels on the edge of the circle are supposed to.
This is the full code of my shader:
#if OPENGL
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0
#define PS_SHADERMODEL ps_4_0
#endif
Texture2D SpriteTexture;
float2 CircleCenter;
float CircleRadius;
sampler2D SpriteTextureSampler = sampler_state
{
Texture = <SpriteTexture>;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 TextureCoordinates : TEXCOORD0;
};
float4 CirclePS(VertexShaderOutput input) : COLOR
{
float distanceToCenter = length(input.Position.xy - CircleCenter);
float sdf = distanceToCenter - CircleRadius;
float alpha = clamp(-sdf, 0, 1);
float4 retval = tex2D(SpriteTextureSampler, input.TextureCoordinates) * input.Color;
retval.a *= alpha;
return retval;
}
float4 CircleOutlinePS(VertexShaderOutput input) : COLOR
{
// Positioning of the outline. -1 for inside radius, 0 for around radius and 1 for outside radius.
int linePosition = -1;
float lineThickness = 2;
float distanceToCenter = length(input.Position.xy - CircleCenter);
float sdf = abs(distanceToCenter - (CircleRadius + lineThickness * linePosition)) - lineThickness / 2;
float alpha = clamp(-sdf, 0, 1);
float4 retval = tex2D(SpriteTextureSampler, input.TextureCoordinates) * input.Color;
retval.a *= alpha;
return retval;
}
technique Circle
{
pass P0
{
PixelShader = compile PS_SHADERMODEL CirclePS();
}
};
technique CircleOutline
{
pass P0
{
PixelShader = compile PS_SHADERMODEL CircleOutlinePS();
}
};
I am using my shader like this, where Pixel
is a white 1x1 Texture2D
and I believe the rest of the names are self explanatory.
void DrawCircle(Vector2 center, float radius, Color color)
{
_spriteBatch.Begin(blendState: BlendState.NonPremultiplied, samplerState: SamplerState.PointClamp, effect: CircleShader, sortMode: SpriteSortMode.Immediate);
CircleShader.CurrentTechnique = CircleShader.Techniques["Circle"];
CircleShader.Parameters["CircleRadius"].SetValue(radius);
CircleShader.Parameters["CircleCenter"].SetValue(FlippedY(center));
Rectangle bounds = new Rectangle((int)(center.X - radius - 1), (int)(center.Y - radius + 1), (int)radius * 2 + 2, (int)radius * 2 + 2);
_spriteBatch.Draw(Pixel, bounds, color);
_spriteBatch.End();
}
The problem does not appear to be related to the amount of pixels drawn. I tried making the bounds the whole screen and it still broke at radius above 256, it just made the whole screen red instead of just the square around the circle.