# Libgdx OpenGL ES pixel shader behaves differently on android and on desktop

I'm currently working on a mobile game that ressembles a snake game ; what I wished to do was use my limited glsl knowledge to write a pixel shader that could efficiently draw a curve with a certain width between a set of a few 2D points.

This is what I managed on desktop using basic libgdx to draw on the whole screen with the shader, and for input.

via GIPHY

To do this, first, I find which point is closest to gl_FragCoord, then, with quite a bit of math, I calculate the equation for a curve between the half-point before that point, and the half-point after it, using this point as control point for the curve... (by half-point I mean the average between it and the point next or before it in the table)

I then use more math to calculate all the local minimums of the distance between the pixel and this curve ; check which are valid, and calculate the minimum distance between the fragment and the snake. Then I can easily check if the pixel is in the width of the snake (named W).

I hope I explained it well, because the code is not annotated at all. I was hoping people had any ideas what could make the difference between the desktop version of libgdx that works perfectly (higher up), and the android version, that does less well...

uniform vec2 stuff;
uniform vec2 points[10];

vec4 fragColor;

vec3 cubicsolve(float a,float b,float c,float d);

void main() {
float tailLength = stuff.y;

fragColor = vec4(0.,0.,0.,1.);
vec4 primColor = vec4(92./255.,158./255.,237./255.,1.);//5C9EED
vec4 degColor = vec4(236./255.,135./255.,192./255.,1.);//EC87C0

int pointNum = int(stuff.x);
vec2 F = gl_FragCoord.xy;
float W = 10.; // width of the snake

degColor = mix(primColor, degColor, 1.- (F.x/1920.+F.y/1080.)/2.);

vec2 alux = points[0]-F;
float first = alux.x*alux.x+alux.y*alux.y;
int key = 0;

for(int i = 1; i<pointNum-1; i++) {
vec2 aux = points[i]-F;
float dist2 = aux.x*aux.x+aux.y*aux.y;
if(dist2<first) {
first=dist2;
key = i;
}
}

float tlim = 1.00;
if(key > pointNum-3) tlim = tailLength;

vec2 t1,mid,t2;
if(key == 0) {
t1 = points[0];
mid = points[1];
t2 = (points[1]+points[2])/2.;
} else {
t1 = (points[key]+points[key-1])/2.;
mid = points[key];
t2 = (points[key]+points[key+1])/2.;
}

vec2 a = (t1-2.*mid+t2);
vec2 b = 2.*(mid-t2);
vec2 c = t2;
vec2 P;

vec2 A = 4.*a*a;
vec2 B = 6.*a*b;
vec2 C = 2.*b*b+4.*a*(c-F);
vec2 D = 2.*b*(c-F);

vec3 get = cubicsolve(A.x+A.y, B.x+B.y, C.x+C.y, D.x+D.y);
float x[3];
x[0] = get.x;x[1] = get.y;x[2] = get.z;

float minDist = 1000.;

for(int i = 0; i<3; i++) {
float xi = x[i];
if(xi>=1.-tlim && xi<=1.) {
//fragColor += vec4(.01,.01,.01,.01);
vec2 temp = a*xi*xi+b*xi+c;
temp = temp * (temp-2.*F) + F*F;
float tempDist = temp.x+temp.y;
if(tempDist < minDist) minDist = tempDist;
}
}
if(true) {
vec2 temp = a*(1.-tlim)*(1.-tlim)+b*(1.-tlim)+c;
temp = temp * (temp-2.*F)+F*F;
float tempsol = temp.x+temp.y;
if(tempsol < minDist) minDist = tempsol;
temp = a*1.*1.+b*1.+c;
temp = temp * (temp-2.*F)+F*F;
tempsol = temp.x+temp.y;
if(tempsol < minDist) minDist = tempsol;
}

if(minDist<W*W) {
fragColor = vec4(1.,1.,1.,1.);
}

vec2 At = points[0];

if((At.x-F.x)*(At.x-F.x)+(At.y-F.y)*(At.y-F.y)<7.*7.) {
fragColor = vec4(0.,0.,0.,0.);
} else if((At.x-F.x)*(At.x-F.x)+(At.y-F.y)*(At.y-F.y)<12.*12.) {
fragColor = vec4(1.,1.,1.,1.);
}

fragColor+=degColor;

for(int i = 0; i<pointNum ; i++) {
vec2 T = points[i];
if((T.x-F.x)*(T.x-F.x)+(T.y-F.y)*(T.y-F.y)<4.*4.) {
fragColor = vec4(1.,0.,0.,1.);
}
}

gl_FragColor = fragColor;
}

vec3 cubicsolve(float a,float b,float c,float d) {
vec3 x = vec3(-1.,-1.,-1.);

if (a == 0.) {
//fragColor = vec4(1.0,0.0,0.0,0.);
if(b == 0.) {
if(c == 0.) {

return x;
}
x.x = -d/c;
return x;
}
float delta = c*c+4.*b*d;
if(delta>0.) {
delta = sqrt(delta);
x.x = (-c+delta)/(2.*b);
x.y = (-c-delta)/(2.*b);
} else if(delta == 0.) {
x.x = -c/(2.*b);
}
return x;
}

if (d == 0.) {
//fragColor = vec4(0.0,1.0,0.0,0.);
x.x = 0.;
float delta = b*b+4.*a*c;
if(delta>0.) {
delta = sqrt(delta);
x.y = (-b+delta)/(2.*a);
x.z = (-b-delta)/(2.*a);
} else if(delta == 0.) {
x.y = -b/(2.*a);
}
return x;
}
b /= a;
c /= a;
d /= a;
float disc, q, r, dum1, s, t, term1, r13;
q = (3.0*c - (b*b))/9.0;
r = -(27.0*d) + b*(9.0*c - 2.0*(b*b));
r /= 54.0;
disc = q*q*q + r*r;
x.x = 0.; //The first root is always real.
term1 = (b/3.0);
if (disc > 0.) { // one root real, two are complex
s = r + sqrt(disc);
s = ((s < 0.) ? -pow(-s, (1.0/3.0)) : pow(s, (1.0/3.0)));
t = r - sqrt(disc);
t = ((t < 0.) ? -pow(-t, (1.0/3.0)) : pow(t, (1.0/3.0)));
x.x = -term1 + s + t;
return x;
}
// End if (disc > 0)
// The remaining options are all real
if (disc == 0.){ // All roots real, at least two are equal.
r13 = ((r < 0.) ? -pow(-r,(1.0/3.0)) : pow(r,(1.0/3.0)));
x.x = -term1 + 2.0*r13;
x.y = -(r13 + term1);
x.z = x.y;
return x;
} // End if (disc == 0)
// Only option left is that all roots are real and unequal (to get here, q < 0)
q = -q;
dum1 = q*q*q;
dum1 = acos(r/sqrt(dum1));
r13 = 2.0*sqrt(q);
x.x = -term1 + r13*cos(dum1/3.0);
x.y = -term1 + r13*cos((dum1 + 2.0*3.14159265359)/3.0);
x.z = -term1 + r13*cos((dum1 + 4.0*3.14159265359)/3.0);
return x;
}

• I'm pretty sure it's a bunch of floating point errors, but I have no idea what to do about it Jul 27, 2016 at 21:12
• Could be caused by precision issues. stackoverflow.com/questions/5366416/…
precision highp float;