I have been trying to put together my own shader in the Shader lab for rounded rectangles, and this is what I have come up with so far. It is pretty dense, and needs to be optimized, but it is able to create a rounded rectangle and smooth the inner and outer border lines in a project or the shader lab, but I would like to move some of it over to the vertex shader for bounds calculation, but I am not entirely sure how to. Right now all of the calculation happens in the fragment shader, but is sees a significant FPS drop when multiple instances are run in a program with smoothing and adding the ellipse areas for the corners. If you want to try it out, you can just past it into the shader lab with the default vertex shader as I didn’t change it.
For Bindings, the stroke and fill are vec4 objects all from 0 - 255, the limits if set to one will prevent the specified corner from being rounded and if zero the corners will be rounded. AntiA is the area of Smoothing on either side of a line. I generally use 0.005. StrokeWidth and radius are in ranges 0 - 1, and position assumes rect mode centered, and accepts a vec4 (x,y,w,h).If you set rectmode to 1 however it assumes rectmode corners.
Please let me know where I can improve it.
Here’s a screenshot of the shader and bindings I’m using
http://www.flickr.com/photos/99433588@N04/11677079456/sizes/o/in/photostream/
//
// A basic fragment shader
//
//Default precision qualifier
precision highp float;
//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform vec4 position;
uniform vec4 fill;
uniform vec4 stroke;
uniform float StrokeWidth;
uniform float radius;
uniform float rectMode;
uniform float AntiA ;
uniform float LimitRD;
uniform float LimitLD;
uniform float LimitRU;
uniform float LimitLU;
//The interpolated vertex color for this fragment
varying lowp vec4 vColor;
//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;
void main()
{
//Sample the texture at the interpolated coordinate
lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;
vec4 Color = vec4(0,0,0,0);
vec2 Center = vec2 (0.5,0.5);
vec4 fill = vec4(fill.r/255.,fill.g/255.,fill.b/255.,fill.a/255.);
vec4 stroke = vec4(stroke.r/255.,stroke.g/255.,stroke.b/255.,stroke.a/255.);
float W = position.z/2.; float H = position.w/2.;
float Radius; float dist = min(W,H); // Keeps Radius within rect bounds
if (radius <= dist) Radius = radius; else if (radius > dist) Radius = dist;
float radius = Radius;
if (rectMode == 1.) // rectMode CORNERS
W,H = (position.z - position.x)/2., (position.w - position.y)/.2;
// ---------------
float L = Center.x - W; float R = Center.x + W;
float U = Center.y + H; float D = Center.y - H;
// Draws Shape Line Border
if (vTexCoord.x >= L - AntiA/2. && vTexCoord.x <= R + AntiA/2.
&& vTexCoord.y >= D - AntiA/2. && vTexCoord.y <= U + AntiA/2.) {
// Interior Fill Drawing
if (vTexCoord.x >= L + StrokeWidth - AntiA/2.
&& vTexCoord.x <= R - StrokeWidth + AntiA/2.
&& vTexCoord.y >= D + StrokeWidth - AntiA/2.
&& vTexCoord.y <= U - StrokeWidth + AntiA/2.){
float DistA = min(distance(vec2(vTexCoord.x, U - StrokeWidth + AntiA/2.),vTexCoord),
distance(vec2(vTexCoord.x,D + StrokeWidth - AntiA/2.),vTexCoord));
float DistB = min(distance(vec2(L + StrokeWidth - AntiA/2.,vTexCoord.y),vTexCoord),
distance(vec2(R - StrokeWidth + AntiA/2.,vTexCoord.y),vTexCoord));
float Dist = min(DistA,DistB);
if (Dist <= AntiA) { float distOut = AntiA - Dist;
if (StrokeWidth > 0.) Color = mix(fill,stroke,(distOut)/AntiA);
else Color = mix(fill,vec4(0,0,0,0),(distOut)/AntiA); }
else Color = fill; }
else if (vTexCoord.x <= L + AntiA/2. || vTexCoord.x >= R - AntiA/2.){
if (vTexCoord.y < U - AntiA/2. && vTexCoord.y > D + AntiA/2. ) {
float Dist = min(distance(vec2(L + AntiA/2.,vTexCoord.y),vTexCoord),
distance(vec2(R - AntiA/2.,vTexCoord.y),vTexCoord));
if (Dist <= AntiA) Color = mix(vec4(0,0,0,0),stroke,(AntiA - Dist)/AntiA); }
else if (vTexCoord.y > U - AntiA/2. || vTexCoord.y < D + AntiA/2.){
vec2 LD = vec2(Center.x - W ,Center.y - H) + vec2(AntiA/2.,AntiA/2.);
vec2 RD = vec2(Center.x + W ,Center.y - H) - vec2(AntiA/2.,-AntiA/2.);
vec2 LU = vec2(Center.x - W ,Center.y + H) + vec2(AntiA/2.,-AntiA/2.);
vec2 RU = vec2(Center.x + W ,Center.y + H) - vec2(AntiA/2.,AntiA/2.);
//Draws Rect Corners
float DistA = min(distance(LU,vTexCoord), distance(RU,vTexCoord));
float DistB = min(distance(LD,vTexCoord), distance(RD,vTexCoord));
float Dist = min(DistA,DistB);
Color = mix(vec4(0,0,0,0),stroke,(AntiA - Dist)/AntiA); } }
else if (vTexCoord.y <= D + AntiA/2. || vTexCoord.y >= U - AntiA/2.){
if (vTexCoord.x < R - AntiA/2. && vTexCoord.x > L - AntiA/2.) {
float Dist = min(distance(vec2(vTexCoord.x, U - AntiA/2.),vTexCoord),
distance(vec2(vTexCoord.x, D + AntiA/2.),vTexCoord));
if (Dist <= AntiA) Color = mix(vec4(0,0,0,0),stroke,(AntiA - Dist)/AntiA); }}
else Color = stroke; }
if (Radius > 0.) { // Rounds Rectangle Sides
// Corner Circle Coordinates //
vec2 LD = vec2(Center.x - W ,Center.y - H) + vec2(Radius,Radius);
vec2 RD = vec2(Center.x + W ,Center.y - H) - vec2(Radius,-Radius);
vec2 LU = vec2(Center.x - W ,Center.y + H) + vec2(Radius,-Radius);
vec2 RU = vec2(Center.x + W ,Center.y + H) - vec2(Radius,Radius);
//Rectangle Interior Pixel Check
bool Area = vTexCoord.y < Center.y + H - StrokeWidth
&& vTexCoord.y > Center.y - H + StrokeWidth && vTexCoord.x > Center.x - W + StrokeWidth
&& vTexCoord.x < Center.x + W - StrokeWidth;
// Inside Drawn Rectangle Fill // --- ---- --- -- ---
if (vTexCoord.x < LD.x && vTexCoord.y < LD.y && LimitLD == 0.
|| vTexCoord.x > RD.x && vTexCoord.y < RD.y && LimitRD == 0.
|| vTexCoord.x < LU.x && vTexCoord.y > LU.y && LimitLU == 0.
|| vTexCoord.x > RU.x && vTexCoord.y > RU.y && LimitRU == 0.
|| Area && vTexCoord.x < LU.x && vTexCoord.y > LU.y && LimitLU == 0. &&
distance(LU,vTexCoord) <= Radius - StrokeWidth + AntiA/2.
|| Area && vTexCoord.x > RU.x && vTexCoord.y > RU.y && LimitRU == 0. &&
distance(RU,vTexCoord) <= Radius - StrokeWidth + AntiA/2.
|| Area && vTexCoord.x < LD.x && vTexCoord.y < LD.y && LimitLD == 0. &&
distance(LD,vTexCoord) <= Radius - StrokeWidth + AntiA/2.
|| Area && vTexCoord.x > RD.x && vTexCoord.y < RD.y && LimitRD == 0. &&
distance(RD,vTexCoord) <= Radius - StrokeWidth + AntiA/2.) {
float DistU = min(distance(LU,vTexCoord),distance(RU,vTexCoord));
float DistD = min(distance(LD,vTexCoord),distance(RD,vTexCoord));
float Dist = min(DistU,DistD);
float distIn = abs(radius - StrokeWidth - AntiA/2. - Dist) ;
float distOut = radius + AntiA/2. - Dist;
if (Dist <= Radius - StrokeWidth + AntiA/2. && Dist >= Radius - StrokeWidth - AntiA/2.)
{if (StrokeWidth > 0.) Color = mix(fill,stroke,((distIn)/AntiA));
else Color = mix(fill,vec4(0,0,0,0),((distIn)/AntiA));}
else if (Dist <= Radius + AntiA/2. && Dist > Radius - StrokeWidth + AntiA/2.)
if (Dist < Radius - AntiA/2.) Color = stroke;
else Color = mix(vec4(0,0,0,0),stroke,(distOut / AntiA));
else if (Dist > Radius + AntiA/2.) Color = vec4(0,0,0,0); };
};
//Set the output color to the texture color
gl_FragColor = Color;
}