Preview
precision highp float;
uniform float time;
uniform vec2 resolution;
out vec4 fragColor;
#define Rot(a) mat2(cos(a),-sin(a),sin(a),cos(a))
#define antialiasing(n) n/min(resolution.y,resolution.x)
#define S(d) 1.-smoothstep(-1.2,1.2, (d)*resolution.y )
#define B(p,s) max(abs(p).x-s.x,abs(p).y-s.y)
#define deg45 .707
#define R45(p) (( p + vec2(p.y,-p.x) ) *deg45)
#define Tri(p,s) max(R45(p).x,max(R45(p).y,B(p,s)))
#define PUV(p) vec2(log(length(p)),atan(p.y/p.x))
#define SkewX(a) mat2(1.0,tan(a),0.0,1.0)
#define SkewY(a) mat2(1.0,0.0,tan(a),1.0)
#define PI 3.14159
#define mapSizeX 17.
#define mapSizeY 20.
#define FONT_H 0.06
#define FONT_THICK 0.02
vec3 pathData[8] = vec3[](
vec3(mapSizeX*0.4, 0.0, -mapSizeY*0.6),
vec3(-mapSizeX*0.3, 0.0, -mapSizeY*0.7),
vec3(-mapSizeX*0.6, 0.0, -mapSizeY*0.3),
vec3(-mapSizeX*0.15, 0.0, -mapSizeY*0.05),
vec3(-mapSizeX*0.35, 0.0, mapSizeY*0.3),
vec3(-mapSizeX*0.15, 0.0, mapSizeY*0.65),
vec3(mapSizeX*0.25, 0.0, mapSizeY*0.75),
vec3(mapSizeX*0.6, 0.0, mapSizeY*0.5)
);
float Hash21(vec2 p) {
p = fract(p*vec2(234.56,789.34));
p+=dot(p,p+34.56);
return fract(p.x+p.y);
}
float noise (vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = Hash21(i);
float b = Hash21(i + vec2(1.0, 0.0));
float c = Hash21(i + vec2(0.0, 1.0));
float d = Hash21(i + vec2(1.0, 1.0));
vec2 u = f*f*(3.0-2.0*f);
return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
float yawBetweenPoints(vec3 a, vec3 b) {
vec2 d = (b - a).xz;
return atan(d.x, d.y);
}
float pitchBetweenPoints(vec3 a, vec3 b) {
vec3 d = b - a;
float h = length(d.xz);
return atan(d.y, h);
}
float lerpAngle(float a, float b, float t) {
vec2 ca = vec2(sin(a), cos(a));
vec2 cb = vec2(sin(b), cos(b));
vec2 c = mix(ca, cb, t);
if(length(c) < 1e-6) return a;
c = normalize(c);
return atan(c.x, c.y);
}
mat3 rotX3(float a) {
float c = cos(a), s = sin(a);
return mat3(1.0, 0.0, 0.0,
0.0, c, s,
0.0, -s, c);
}
mat3 rotY3(float a) {
float c = cos(a), s = sin(a);
return mat3(c, 0.0, -s,
0.0,1.0, 0.0,
s, 0.0, c);
}
mat3 rotZ3(float a) {
float c = cos(a);
float s = sin(a);
return mat3(
c, -s, 0.0,
s, c, 0.0,
0.0, 0.0, 1.0
);
}
// thx, iq! https://iquilezles.org/articles/distfunctions2d/
float sdPolygon(vec2[4] v, in vec2 p )
{
float d = dot(p-v[0],p-v[0]);
float s = 1.0;
for( int i=0, j=4-1; i<4; j=i, i++ )
{
vec2 e = v[j] - v[i];
vec2 w = p - v[i];
vec2 b = w - e*clamp( dot(w,e)/dot(e,e), 0.0, 1.0 );
d = min( d, dot(b,b) );
bvec3 c = bvec3(p.y>=v[i].y,p.y<v[j].y,e.x*w.y>e.y*w.x);
if( all(c) || all(not(c)) ) s*=-1.0;
}
return s*sqrt(d);
}
// thx, iq! https://iquilezles.org/articles/distfunctions2d/
float sdHexagon( in vec2 p, in float r )
{
const vec3 k = vec3(-0.866025404,0.5,0.577350269);
p = abs(p);
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
return length(p)*sign(p.y);
}
//thx Shane! getting the hex uv logic from the Shane's implementation here: https://www.shadertoy.com/view/Xljczw
const vec2 s = vec2(1.7320508, 1);
vec4 getHex(vec2 p){
vec4 hC = floor(vec4(p, p - vec2(1, .5))/s.xyxy) + .5;
vec4 h = vec4(p - hC.xy*s, p - (hC.zw + .5)*s);
return dot(h.xy, h.xy)<dot(h.zw, h.zw) ? vec4(h.xy, hC.xy) : vec4(h.zw, hC.zw + .5);
}
float lineTo(vec2 p, vec2 a, vec2 b){
float k = dot(p-a,b-a)/dot(b-a,b-a);
vec2 distanceToPoint = mix(a,b,clamp(k,0.,1.));
return distance(p,distanceToPoint);
}
vec2 getSphereMap(vec2 p, float size){
p*=size;
float r = dot(p, p);
float z = sqrt(1.0 - r);
vec3 q = vec3(p, z);
//q.xz*=Rot(radians(53.+20.*time*0.5));
vec3 normal = normalize(q);
float longitude = atan(normal.x, normal.z);
float latitude = asin(normal.y);
float u = longitude / (2. * PI) + 0.5;
float v = latitude / (2.*PI) + 0.5;
p = vec2(u,v);
p -= 0.5;
p*=size;
return p;
}
float cA(vec2 p){
p.x = abs(p.x);
float h = FONT_H;
float d = lineTo(p,vec2(0.,h),vec2(h,-h))-FONT_THICK;
return d;
}
float cF(vec2 p){
float h = FONT_H;
float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(-h*0.25,0.),vec2(h,0.))-FONT_THICK;
d = min(d,d2);
return d;
}
float cG(vec2 p){
vec2 prevP = p;
float h = FONT_H;
float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
p.y = abs(p.y);
float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
d = min(d,d2);
p = prevP;
d2 = lineTo(p,vec2(-h*0.25,0.),vec2(h,0.))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,0.),vec2(h,-h))-FONT_THICK;
d = min(d,d2);
return d;
}
float cI(vec2 p){
vec2 prevP = p;
float h = FONT_H;
float d = lineTo(p,vec2(0.,h),vec2(0.,-h))-FONT_THICK;
return d;
}
float cL(vec2 p){
vec2 prevP = p;
float h = FONT_H;
float d = lineTo(p,vec2(-h,h),vec2(-h,-h))-FONT_THICK;
float d2 = lineTo(p,vec2(-h,-h),vec2(h,-h))-FONT_THICK;
d = min(d,d2);
return d;
}
float cN(vec2 p){
vec2 prevP = p;
float h = FONT_H;
p.x = abs(p.x);
float d = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
p = prevP;
float d2 = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
d = min(d,d2);
return d;
}
float cO(vec2 p){
vec2 prevP = p;
float h = FONT_H;
p.x = abs(p.x);
float d = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
p = prevP;
p.y = abs(p.y);
float d2 = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
d = min(d,d2);
return d;
}
float cP(vec2 p){
float h = FONT_H;
float d = lineTo(p,vec2(-h,0.0),vec2(-h,-h))-FONT_THICK;
float d2 = lineTo(p,vec2(-h,h),vec2(h,h))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(-h,0.),vec2(h,0.))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,h),vec2(h,0.))-FONT_THICK;
d = min(d,d2);
return d;
}
float c2(vec2 p){
vec2 prevP = p;
float h = FONT_H;
p.y = abs(p.y);
float d = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
p = prevP;
float d2 = lineTo(p,vec2(h,0.),vec2(-h,0.))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,h),vec2(h,0.))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(-h,0.),vec2(-h,-h))-FONT_THICK;
d = min(d,d2);
return d;
}
float c3(vec2 p){
vec2 prevP = p;
float h = FONT_H;
p.y = abs(p.y);
float d = lineTo(p,vec2(h,h),vec2(-h,h))-FONT_THICK;
p = prevP;
float d2 = lineTo(p,vec2(h*0.25,0.),vec2(-h,0.))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,h),vec2(h,-h))-FONT_THICK;
d = min(d,d2);
return d;
}
float c4(vec2 p){
float h = FONT_H;
float d = lineTo(p,vec2(-h,h),vec2(-h,0.0))-FONT_THICK;
float d2 = lineTo(p,vec2(h,0.0),vec2(-h,0.0))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,0.0),vec2(h,-h))-FONT_THICK;
d = min(d,d2);
d2 = lineTo(p,vec2(h,h),vec2(h,h*0.75))-FONT_THICK;
d = min(d,d2);
return d;
}
float c5(vec2 p){
vec2 prevP = p;
p.y*=-1.;
float d = c2(p);
return d;
}
float c6(vec2 p){
vec2 prevP = p;
p.y*=-1.;
float d = cP(p);
return d;
}
float c7(vec2 p){
vec2 prevP = p;
p*=-1.;
float d = cL(p);
return d;
}
float c8(vec2 p){
vec2 prevP = p;
float h = FONT_H;
float d = cO(p);
float d2 = lineTo(p,vec2(-h,0.),vec2(h,0.0))-FONT_THICK;
d = min(d,d2);
return d;
}
float c9(vec2 p){
vec2 prevP = p;
p.x*=-1.;
float d = cP(p);
return d;
}
float drawNumbers(vec2 p, int char){
float d = 10.;
if(char == 0) {
d = cO(p);
} else if(char == 1){
d = cI(p);
} else if(char == 2){
d = c2(p);
} else if(char == 3){
d = c3(p);
} else if(char == 4){
d = c4(p);
} else if(char == 5){
d = c5(p);
} else if(char == 6){
d = c6(p);
} else if(char == 7){
d = c7(p);
} else if(char == 8){
d = c8(p);
} else if(char == 9){
d = c9(p);
}
return d;
}
float go(vec2 p){
float s = FONT_H+0.03;
float d = cG(p-vec2(-s,0.0));
float d2 = cO(p-vec2(s,0.0));
d = min(d,d2);
return d;
}
float c25(vec2 p){
float s = FONT_H+0.03;
float d = c2(p-vec2(-s,0.0));
float d2 = c5(p-vec2(s,0.0));
d = min(d,d2);
return d;
}
float animNumbers(vec2 p, float n){
float s = FONT_H+0.03;
float d = drawNumbers(p-vec2(-s,0.0),int(mod(time*7.+n,10.)));
float d2 = drawNumbers(p-vec2(s,0.0),int(mod(time*10.+n,10.)));
d = min(d,d2);
return d;
}
float finallap(vec2 p){
p*=1.5;
float s = FONT_H+0.03;
float d = cF(p-vec2(-s*7.5,0.0));
float d2 = cI(p-vec2(-s*5.5,0.0));
d = min(d,d2);
d2 = cN(p-vec2(-s*3.5,0.0));
d = min(d,d2);
d2 = cA(p-vec2(-s*1.5,0.0));
d = min(d,d2);
d2 = cL(p-vec2(-s*-0.5,0.0));
d = min(d,d2);
d2 = cL(p-vec2(s*3.5,0.0));
d = min(d,d2);
d2 = cA(p-vec2(s*5.5,0.0));
d = min(d,d2);
d2 = cP(p-vec2(s*7.5,0.0));
d = min(d,d2);
return d;
}
float goal(vec2 p){
float s = FONT_H+0.03;
float d = cG(p-vec2(-s*3.,0.0));
float d2 = cO(p-vec2(-s,0.0));
d = min(d,d2);
d2 = cA(p-vec2(s,0.0));
d = min(d,d2);
d2 = cL(p-vec2(s*3.0,0.0));
d = min(d,d2);
return d;
}
float times(vec2 p){
p*=2.0;
float s = FONT_H+0.03;
float d = drawNumbers(p-vec2(-s*3.5,0.0),int(mod(time,10.)));
float d2 = drawNumbers(p-vec2(-s*1.5,0.0),int(mod(time*5.,10.)));
d = min(d,d2);
d2 = drawNumbers(p-vec2(s*1.5,0.0),int(mod(time*10.,10.)));
d = min(d,d2);
d2 = drawNumbers(p-vec2(s*3.5,0.0),int(mod(time*20.,10.)));
d = min(d,d2);
p*=SkewX(radians(-15.));
p.x+=0.02;
p.x = abs(p.x)-0.015;
p.y-=0.07;
d2 = B(p,vec2(0.01,0.03));
d = min(d,d2);
return d;
}
float speedMeter(vec2 p){
p*=3.0;
float s = FONT_H+0.03;
float d = drawNumbers(p-vec2(-s*2.,0.0),3);
float d2 = drawNumbers(p,int(mod(time*11.,10.)));
d = min(d,d2);
d2 = drawNumbers(p-vec2(s*2.,0.0),int(mod(time*16.,10.)));
d = min(d,d2);
return d;
}
float power(vec2 p){
float d = abs(B(p,vec2(0.195,0.02)))-0.005;
float d2 = p.x-sin(time*0.3)*0.1;
d2 = max(abs(p.y)-0.008,d2);
d2 = max(-p.x-0.18,d2);
d = min(d,d2);
return d;
}
vec3 startLine(vec2 p, vec3 col, float morph){
vec2 prevP = p;
float d = B(p,vec2(1.3,0.28));
col = mix(col,vec3(0.7),mix(0.,S(d),morph));
p = mod(p,0.4)-0.2;
d = B(p,vec2(0.1));
p = prevP;
p+=0.2;
p = mod(p,0.4)-0.2;
float d2 = B(p,vec2(0.1));
d = min(d,d2);
p = prevP;
d = max(B(p,vec2(1.3,0.28)),d);
col = mix(col,vec3(0.),mix(0.,S(d),morph));
return col;
}
float arrow(vec2 p){
vec2 prevP = p;
p.x*=1.5;
p.y*=-1.;
p.y-=0.25;
float d = Tri(p,vec2(0.5));
p.y+=0.25;
float d2 = Tri(p,vec2(0.5));
d = max(-d2,d);
p = prevP;
p.y-=0.35;
p.x*=1.5;
p.y*=-1.;
p.y-=0.25;
d2 = Tri(p,vec2(0.5));
p.y+=0.25;
float d3 = Tri(p,vec2(0.5));
d2 = max(-d3,d2);
d = min(d,d2);
return d;
}
float arrows(vec2 p){
p.y-=time*0.1;
p.y*=-1.;
p.y = mod(p.y,0.5)-0.25;
p*=2.;
float d = arrow(p);
return d;
}
float arrows2(vec2 p){
p.y=abs(p.y);
p.y-=time*0.1;
p.y = mod(p.y,0.1)-0.05;
p.x*=2.;
float d = Tri(p,vec2(0.05));
return d;
}
float pattern1(vec2 p, float n){
vec2 prevP = p;
float d = 10.;
for(int i = 1; i<3; i++){
p*=Rot(radians(n*float(i)*30.*time));
p = abs(p)-float(i)*0.1;
p*=Rot(radians(n*float(i)*30.));
float d2 = arrows(p);
d = min(d,d2);
}
return d;
}
float pattern2(vec2 p, float n){
p*=Rot(radians(45.));
p.x+=time*(0.5*n);
p.x = mod(p.x,0.2)-0.1;
float d = abs(p.x)-0.05;
return d;
}
float obstacle(vec2 p, vec2 c, float r) {
vec2 q = p - c;
vec2 prevQ = q;
q*=Rot(radians(30.*time*2.));
float d = abs(length(q) - r)-0.02;
d = max(-(abs(q.y)-0.05),d);
q = prevQ;
float d2 = length(q) - (r*0.8);
d = min(d,d2);
q = prevQ;
q*=Rot(radians(-20.*time*1.8));
q.x = abs(q.x)-0.1;
d2 = length(q)-0.02;
d = max(-d2,d);
return d;
}
float drawHexBg(vec2 p){
p.x+=time*0.5;
vec4 hgr = getHex(p);
vec4 prevHgr = hgr;
float n = Hash21(hgr.zw);
float d = 10.;
float dir = 1.;
if(n<0.5){
dir = -1.;
}
float s = 0.07;
hgr.xy*=Rot(radians(30.*dir));
hgr.y = abs(hgr.y)-0.55;
float d2 = abs(length(hgr.xy)-0.275)-s;
d = min(abs(d)-0.01,d2);
hgr.y +=0.09;
hgr.xy*=Rot(radians(30.*time*2.+n));
d2 = length(hgr.xy)-0.07;
d2 = abs(d2)-0.015;
d2 = max(-(abs(hgr.x)-0.02),d2);
d = min(d,d2);
hgr= prevHgr;
hgr.xy*=Rot(radians(60.*-dir));
d2 = B(hgr.xy,vec2(s,0.6));
d = min(d,d2);
hgr.x = abs(hgr.x)-0.15;
d2 = arrows2(hgr.xy);
d = min(d,d2);
return d;
}
vec3 bg(vec2 p, vec3 col, bool isFinal){
p*=20.;
p.y*=0.6;
p.y-=time*0.2;
vec4 hgr = getHex(p);
vec4 prevHgr = hgr;
float n = Hash21(hgr.zw);
float d = 10.;
float d2 = 10.;
if(n<0.3){
d2 = pattern1(hgr.xy,n);
} else if(n>=0.3 && n<0.6){
d2 = pattern2(hgr.xy,n);
} else {
d = abs(sdHexagon(hgr.xy, 0.35))-0.05;
if(!isFinal){
float d3 = c25(hgr.xy*0.7);
d = min(d,d3);
} else {
float d3 = animNumbers(hgr.xy*0.7,n*5.);
d = min(d,d3);
}
}
d = min(d,d2);
d = max(-(abs(sdHexagon(hgr.xy, 0.46))-0.05),d);
col = mix(col,vec3(0.5),S(d));
return col;
}
vec2 sdRepeatNBetween(vec2 p, vec2 a, vec2 b, float r, int N) {
vec2 dir = b - a;
float len2 = dot(dir, dir);
float k = dot(p - a, dir) / len2;
float idx = floor(k * float(N - 1) + 0.5);
idx = clamp(idx, 0.0, float(N - 1));
vec2 center = a + dir * (idx / float(N - 1));
return center;
}
float obstacles(vec2 p, vec2 a, vec2 b){
float r = 0.25;
float num = distance(a,b) / (2.0 * r);
vec2 c = sdRepeatNBetween(p,a,b,r,int(ceil(num)));
float d = obstacle(p,c,r);
return d;
}
float centerObjects(vec2 p, vec2 a, vec2 b){
float r = 1.5;
float num = distance(a,b) / (2.0 * r);
vec2 c = sdRepeatNBetween(p,a,b,r,int(ceil(num)));
vec2 dir = b - a;
float angle = atan(dir.y, dir.x)+radians(90.);
float d = arrow(0.5*(p-c)*Rot(-angle));
float m = length(p-a)-r;
d = max(-m,d);
m = length(p-b)-r;
d = max(-m,d);
return d;
}
float sideRepeatLines(vec2 p, float dist){
vec2 prevP = p;
p.y-=time*1.2;
p.y = mod(p.y,1.2)-0.6;
p*= SkewY(radians(-45.));
float d = B(p,vec2(0.1,0.4));
return max((abs(prevP.y)-dist),d);
}
float sideLines(vec2 p, float dist, float w){
p.x = abs(p.x)-(w*0.25);
float d = sideRepeatLines(p,dist*0.3);
return d;
}
vec2 calcNormal(vec2 prev, vec2 current, vec2 next) {
vec2 dir = vec2(0.);
if (prev != current) dir += current - prev;
if (next != current) dir += next - current;
return normalize(vec2(-dir.y, dir.x));
}
vec3 courseMap(vec2 p, vec3 bgCol, vec3 col, float morph) {
float d = B(p, vec2(mapSizeX, mapSizeY));
col = mix(col, bgCol, S(d));
d = max(d,drawHexBg(p*0.5));
col = mix(col, vec3(1.), 1.-smoothstep(-0.01,0.01,d));
float lsize = 1.7;
float lsize2 = 2.2;
const int pathCount = pathData.length();
vec2 normals[pathCount];
for (int i = 0; i < pathCount; i++) {
vec2 prev = pathData[(i + pathCount - 1) % pathCount].xz;
vec2 current = pathData[i].xz;
vec2 next = pathData[(i + 1) % pathCount].xz;
normals[i] = calcNormal(prev, current, next);
}
float d2 = 10.;
float d3 = 10.;
float d4 = 10.;
float d5 = 10.;
for (int i = 0; i < pathCount; i++) {
vec2 a = pathData[i].xz;
vec2 b = pathData[(i + 1) % pathCount].xz;
vec2 nA = normals[i];
vec2 nB = normals[(i + 1) % pathCount];
float ld = sdPolygon( vec2[4](a + nA*lsize2, b + nB*lsize2, b - nB*lsize2,a - nA*lsize2),p);
d2 = min(ld,d2);
float od = obstacles(p, a + nA*lsize2, b + nB*lsize2);
d3 = min(od,d3);
od = obstacles(p, a - nA*lsize2, b - nB*lsize2);
d3 = min(od,d3);
od = centerObjects(p, a, b);
d4 = min(od,d4);
vec2 dir = b - a;
float angle = atan(dir.y, dir.x)+radians(90.);
vec2 midP = p-((a+b)*0.5);
float w = distance(a + nA*lsize2,a - nA*lsize2);
od = sideLines(midP*Rot(-angle),distance(a,b),w);
d5 = min(od,d5);
}
col = mix(col, vec3(0.05), mix(0.,S(abs(d2)-0.5),morph));
col = mix(col, vec3(0.45), mix(0.,S(d2),morph)); // fix the small gaps.
col = mix(col, vec3(0.3)+noise(p*20.*Rot(radians(45.)))*0.05, mix(0.,S(d2),morph));
vec2 dir = pathData[1].xz - pathData[0].xz;
float angle = atan(dir.y, dir.x)+radians(90.);
col = startLine((p-mix(pathData[0].xz,pathData[1].xz,0.12))*Rot(-angle),col,morph);
col = mix(col, vec3(0.7), mix(0.,S(d3),morph));
col = mix(col, vec3(0.7), mix(0.,S(d4),morph));
col = mix(col, vec3(0.6), mix(0.,S(d5),morph));
return col;
}
vec3 courseMapForUI(vec2 p, vec3 bgCol, vec3 col, vec3 camPos) {
float lsize = 1.2;
const int pathCount = pathData.length();
float d = 10.;
for (int i = 0; i < pathCount; i++) {
vec2 a = pathData[i].xz;
vec2 b = pathData[(i + 1) % pathCount].xz;
float ld = lineTo(p, a, b) - lsize;
d = min(d,ld);
}
col = mix(col, vec3(1.), S(d));
col = mix(col, vec3(0.2), S(abs(d)-0.2));
d = length(p - camPos.xz) - 0.8;
col = mix(col, vec3(0.3), S(d));
return col;
}
vec3 carDoor(vec2 p, vec3 col){
vec2 prevP = p;
float a = radians(45.);
float d = B(p,vec2(0.013,0.15));
p.x = abs(p.x);
p.y = abs(p.y)-0.12;
d = max(dot(p,vec2(cos(a),sin(a))),d);
col = mix(col, vec3(0.),S(d));
p = prevP;
d = B(p,vec2(0.005,0.1));
col = mix(col, vec3(0.9),S(d));
return col;
}
vec3 carEngineFire(vec2 p, vec3 col){
p.x*=4.;
p.y*=-0.9;
p.x+=noise(p*Rot(radians(time*100.))*60.)*0.08;
float d = Tri(p,vec2(0.1));
col = mix(col, vec3(0.5),1.-smoothstep(0.,0.05,d));
return col;
}
vec3 carMain(vec2 p, vec3 col, float leftVal, float rightVal){
vec2 prevP = p;
float a = radians(45.);
float d = B(p-vec2(0.,0.05),vec2(0.08,0.1));
p.x = abs(p.x);
p.y-=0.19;
d = max(dot(p,vec2(cos(a),sin(a))),d);
p = prevP;
float d2 = B(p,vec2(0.17,0.06));
d = min(d,d2);
a = radians(-45.);
p.y+=0.05;
d2 = B(p,vec2(0.07,0.06));
p.x = abs(p.x);
p.y+=0.11;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
d = min(d,d2);
p = prevP;
p.x = abs(p.x)-0.12;
a = radians(-45.);
p.y+=0.035;
d2 = B(p,vec2(0.05,0.06));
p.x = abs(p.x);
p.y+=0.08;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
d = min(d,d2);
p = prevP;
p.x = abs(p.x)-0.12;
a = radians(45.);
p.y-=0.03;
d2 = B(p,vec2(0.035,0.06));
p.x = abs(p.x);
p.y-=0.075;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
d = min(d,d2);
col = mix(col, vec3(0.),S(d));
p = prevP;
p.y-=0.01;
a = radians(45.);
d = B(p,vec2(0.05,0.035));
p.x = abs(p.x)-0.06;
p.y = abs(p.y);
d = max(dot(p,vec2(cos(a),sin(a))),d);
p = prevP;
p.y+=0.05;
p.y = abs(p.y)-0.008;
d2 = B(p,vec2(0.05,0.005));
d = min(d,d2);
p = prevP;
p.y+=0.082;
a = radians(-45.);
d2 = B(p,vec2(0.06,0.012));
p.x = abs(p.x)-0.062;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
p = prevP;
p.y+=0.07;
a = radians(-45.);
float mask = B(p,vec2(0.05,0.012));
p.x = abs(p.x)-0.055;
mask = max(dot(p,vec2(cos(a),sin(a))),mask);
d2 = max(-mask,d2);
d = min(d,d2);
p = prevP;
p.y-=0.095;
a = radians(45.);
d2 = B(p,vec2(0.06,0.04));
p.x = abs(p.x)-0.07;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
p = prevP;
p.y-=0.06;
a = radians(45.);
mask = B(p,vec2(0.045,0.016));
p.x = abs(p.x)-0.045;
mask = max(dot(p,vec2(cos(a),sin(a))),mask);
d2 = max(-mask,d2);
d = min(d,d2);
p = prevP;
p.x = abs(p.x)-0.12;
p.y+=0.035;
a = radians(45.);
d2 = B(p,vec2(0.032,0.045));
p.x = abs(p.x)-0.055;
p.y = abs(p.y);
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
d = min(d,d2);
p = prevP;
p.x = abs(p.x)-0.12;
p.y-=0.07;
d2 = B(p,vec2(0.025,0.011));
p.x = abs(p.x)-0.02;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
d = min(d,d2);
p = prevP;
p.x = abs(p.x)-0.12;
p.y-=0.027;
a = radians(45.);
d2 = B(p,vec2(0.05,0.02));
p.x = abs(p.x)-0.04;
d2 = max(dot(p,vec2(cos(a),sin(a))),d2);
p = prevP;
p.x = abs(p.x)-0.12;
p.y-=0.008;
a = radians(45.);
mask = B(p,vec2(0.04,0.016));
p.x = abs(p.x)-0.03;
mask = max(dot(p,vec2(cos(a),sin(a))),mask);
d2 = max(-mask,d2);
d = min(d,d2);
col = mix(col, vec3(0.9),S(d));
p = prevP;
float targetY = 0.03;
// left door
col = carDoor(p-vec2(-0.18,leftVal*targetY),col);
// right door
col = carDoor(p-vec2(0.18,rightVal*targetY),col);
p.x = abs(p.x)-0.13;
p.y+=0.2;
col = carEngineFire(p,col);
return col;
}
vec3 car(vec2 p, vec3 col, float leftVal, float rightVal){
vec2 prevP = p;
p.x*= 0.5;
p.y*= 2.5;
p.y+=0.25;
float d = length(p)-0.1;
col = mix(col, col*vec3(0.7),S(d));
p = prevP;
p.y+=sin(time*5.)*0.01;
float targetSknewX = 10.;
p*=SkewX(radians(leftVal*targetSknewX));
p*=SkewX(radians(rightVal*-targetSknewX));
col = carMain(p-vec2(0.0,0.03),col,leftVal,rightVal);
return col;
}
vec3 carEnergy(vec2 p, vec3 col){
vec2 prevP = p;
p.x*= 0.5;
p.y*= 2.5;
p.y+=time*2.;
p.y = mod(p.y,0.22)-0.11;
float d = abs(length(p)-0.1)-0.015;
p = prevP;
float mask = B(p-vec2(0.0,0.1),vec2(0.25,0.4));
vec2 cp = p-vec2(0.0,-0.35);
cp.y*=2.;
float d2 = length(cp)-0.25;
mask = min(mask,d2);
p = prevP;
d = max(mask,d);
col = mix(col, col*vec3(2.),S(d));
return col;
}
float carEffectParts(vec2 p){
vec2 prevP = p;
p.x*=3.;
float d = length(p)-0.4;
return d;
}
vec3 carEffect(vec2 p, vec2 p2, vec3 col){
p.y+=time*2.;
vec2 prevP = p;
p*=6.;
vec2 id = floor(p);
vec2 gr = fract(p)-0.5;
float n = Hash21(id);
float d = carEffectParts(gr);
if(n<0.5)d = 10.;
d = max((length(p2)-0.22),d);
col = mix(col,col*vec3(2.),S(d));
return col;
}
float cubicInOut(float t) {
return t < 0.5
? 4.0 * t * t * t
: 0.5 * pow(2.0 * t - 2.0, 3.0) + 1.0;
}
float getTime(float t, float duration){
return clamp(t,0.0,duration)/duration;
}
vec3 effectOverlay1(vec2 p, vec2 p2, vec3 col){
vec2 id = floor(p);
vec2 gr = fract(p)-0.5;
float n = Hash21(id);
float d = (n<0.5) ? 10. :B(gr,vec2(0.5*n,0.05*n));
vec3 ecol = col+(vec3(mix(0.0,1.,gr.x+0.5))* length(p2)-0.1);
col = mix(col,ecol,S(d));
return col;
}
vec3 effectOverlay2(vec2 p, vec2 p2, vec3 col){
vec2 id = floor(p);
vec2 gr = fract(p)-0.5;
float n = Hash21(id);
gr *= n;
float d = (n<0.5) ? 10. : length(gr)-0.1;
vec3 ecol = col+(vec3(1.0)* length(p2)-0.2);
col = mix(col,ecol,S(d));
return col;
}
vec3 windEffect(vec2 p, vec3 col, float alpha, float s){
vec2 prevP = p;
p*=s;
p.y+=time*5.;
vec2 id = floor(p);
vec2 gr = fract(p)-0.5;
float n = Hash21(id);
gr *= n*2.;
gr.x*=2.;
float d = (n<0.5) ? 10. : arrow(gr);
p = prevP;
d = max(B(p, vec2(mapSizeX, mapSizeY)),d);
col = mix(col,col+vec3(alpha),S(d));
return col;
}
vec3 ui(vec2 p, vec3 col){
vec2 prevP = p;
float x = 0.58;
float d = times(p-vec2(x,0.2));
col = mix(col,vec3(1.),S(d));
d = B(p-vec2(x,0.275),vec2(0.2,0.005));
col = mix(col,vec3(1.),S(d));
d = speedMeter(p-vec2(x+0.11,0.33));
col = mix(col,vec3(1.),S(d));
d = power(p-vec2(x,0.41));
col = mix(col,vec3(1.),S(d));
return col;
}
vec3 drawRaceScene(vec2 p, vec3 col){
float speed = 0.55;
float totalSegs = float(pathData.length());
float firstSceneTotal = 1.5;
float endSceneTotal = 3.;
float totalLaps = 2.0;
float raceTotal = totalSegs*totalLaps;
float sceneTotal = firstSceneTotal+raceTotal+endSceneTotal;
float t = time*speed;
float scene = mod(t,sceneTotal);
int raceRound = 1;
int effect = 0;
float initialUiX = 0.6;
bool isFinal = false;
if(scene<sceneTotal){
float f = mod(scene, firstSceneTotal+totalSegs)-firstSceneTotal;
if(scene>=firstSceneTotal+totalSegs && scene<firstSceneTotal+raceTotal){
f = mod(scene, firstSceneTotal+raceTotal)-(firstSceneTotal+totalSegs);
}
int seg = int(floor(f));
float segT = fract(f);
float endAnimStart = firstSceneTotal+raceTotal+(endSceneTotal-2.);
float initialCarY = -0.5;
float initialRot = radians(90.);
float initialHeight = -8.;
float initialMapX = -40.;
float courseMorph = 0.;
float carScale = 1.;
float easeValue = 0.;
float duration = 1.;
float time = scene;
if(scene<firstSceneTotal+0.1){
time = getTime(time,duration);
float anim = cubicInOut(time);
easeValue = 90.-(anim*90.);
initialHeight = -8.+(anim*8.);
initialRot = radians(easeValue);
initialCarY = -0.5+(anim*0.5);
initialUiX= 0.6-(anim*0.6);
initialMapX = -40.+(anim*40.);
courseMorph = anim;
} else if(scene >=firstSceneTotal+raceTotal && scene < endAnimStart){
initialRot = 0.0;
initialHeight = 0.0;
initialUiX = 0.0;
initialMapX = 0.0;
time = getTime(time-(firstSceneTotal+raceTotal),duration);
float anim = time;
initialCarY = (anim*0.25);
carScale = 1.+(anim*0.5);
courseMorph = 1.;
} else if(scene >= endAnimStart && scene < sceneTotal){
time = getTime(time-endAnimStart,duration*0.7);
float anim = cubicInOut(time);
easeValue = anim*90.;
initialHeight = -(anim*8.);
initialRot = radians(easeValue);
initialCarY = 0.25-(anim*0.75);
initialUiX= (anim*0.6);
initialMapX = -(anim*40.);
carScale = 1.5-(anim*0.5);
courseMorph = 1.-anim;
}
if(scene>=firstSceneTotal+0.1 && scene<firstSceneTotal+raceTotal){
initialRot = 0.0;
initialHeight = 0.0;
initialCarY = 0.0;
initialUiX = 0.0;
initialMapX = 0.0;
courseMorph = 1.;
}
if(scene<firstSceneTotal){
seg = 0;
segT = 0.0;
} else if(scene>=firstSceneTotal+raceTotal){
seg = 0;
segT = 0.0;
}
// display race round
if(scene<firstSceneTotal-0.25){
raceRound = -1;
} else if(scene>=firstSceneTotal-0.25 && scene<=firstSceneTotal+0.3){
raceRound = 1;
} else if(scene>=firstSceneTotal+totalSegs-0.25 && scene<=firstSceneTotal+totalSegs+0.4){
raceRound = 2;
} else if(scene>=firstSceneTotal+raceTotal && scene<endAnimStart){
raceRound = 3;
} else {
raceRound = 0;
}
// check final lap
if(scene>=firstSceneTotal+totalSegs){
isFinal = true;
}
// effect
if(scene>=firstSceneTotal+(totalSegs-1.0) && scene < firstSceneTotal+(totalSegs-0.25)){
effect = 1;
} else if(scene>=firstSceneTotal+(raceTotal-1.0) && scene < firstSceneTotal+(raceTotal-0.25)){
effect = 2;
}
int segs = int(totalSegs);
int i0 = seg;
int i1 = (seg + 1) % segs;
int i2 = (seg + 2) % segs;
vec3 A = pathData[i0];
vec3 B = pathData[i1];
vec3 C = pathData[i2];
vec3 camPos = mix(A, B, segT);
float yawAB = yawBetweenPoints(A, B);
float yawBC = yawBetweenPoints(B, C);
float blendT = smoothstep(0.7, 1.0, segT);
float yaw = lerpAngle(yawAB, yawBC, blendT);
float pitchAB = pitchBetweenPoints(A, B);
float pitchBC = pitchBetweenPoints(B, C);
float pitch = lerpAngle(pitchAB, pitchBC, blendT);
mat3 camRotation = rotY3(yaw) * rotX3((pitch+radians(10.))+initialRot);
vec3 ray = normalize(vec3(p, 1.0));
ray = camRotation * ray;
float z = ray.z;
vec2 proj = ray.xy / z;
float d = 10.;
float groundHeight = -0.5+initialHeight;
float t = (groundHeight - camPos.y) / ray.y;
vec3 hit = camPos + ray * t;
// render background
vec3 ray2 = ray;
vec3 r = normalize(ray);
r.x=abs(r.x);
float newX = atan(r.x, r.z) / (2.0*PI) + 0.5;
float newY = asin(clamp(r.y, -1.0, 1.0)) / PI + 0.5;
vec2 bgp = vec2(newX,newY);
col = bg(vec2(newX,newY),col,isFinal);
// render course map
if(t > 0.0) {
col = courseMap(hit.xz,vec3(0.15),col,courseMorph);
if(scene>=firstSceneTotal-0.25 && scene<endAnimStart){
col = windEffect(hit.xz,col,0.05,0.9);
}
} else {
groundHeight = -3.;
t = (groundHeight - camPos.y) / ray.y;
hit = camPos + ray * t;
if(scene>=firstSceneTotal-0.25 && scene<endAnimStart){
col = windEffect(hit.xz*0.8,col,0.3,0.5);
}
}
// render ui course map
float spriteZ = 7.0;
col = courseMapForUI((p*90.)-vec2(-59.+initialMapX,-25.),vec3(1.),col,camPos);
// render effets
vec2 ep = ray.xy;
ep.x = p.x;
ep*=Rot(radians(3.*time*(effect == 1?1.:30.)));
ep = PUV(ep);
ep.x-=time*5.;
ep*=2.54;
if(effect == 1){
col = effectOverlay1(ep,p,col);
} else if(effect == 2){
col = effectOverlay2(ep,p,col);
}
// render car
float yawDelta = yawBC - yawAB;
yawDelta = mod(yawDelta + PI, PI*2.) - PI;
float leftVal = yawDelta < -0.001 ? 1.0 : 0.0;
float rightVal = yawDelta > 0.001 ? 1.0 : 0.0;
float turnBlend = smoothstep(0.5, 1.0, segT);
leftVal *= turnBlend;
rightVal *= turnBlend;
col = car((p- vec2(0.,-0.3+initialCarY))*carScale,col,leftVal,rightVal);
if(scene>=firstSceneTotal+totalSegs+1. && scene<firstSceneTotal+totalSegs+1.7){
col = carEnergy(p,col);
}
if(scene>=firstSceneTotal+totalSegs+1.7 && scene<firstSceneTotal+totalSegs+7.){
col = carEffect(getSphereMap(p-vec2(0.,-0.25),4.),p-vec2(0.,-0.25),col);
}
}
// display round text
if(raceRound == -1){
// count down
float count = 3.0-((scene/firstSceneTotal-0.25)*3.0);
float d = drawNumbers(p,int(count));
col = mix(col,vec3(0.2),1.-smoothstep(0.,0.025,d));
col = mix(col,vec3(1.),S(d));
col = mix(col,vec3(0.),S(abs(d)-0.003));
} else if(raceRound == 1){
// GO
float d = go(p);
col = mix(col,vec3(1.),S(d));
col = mix(col,vec3(0.),S(abs(d)-0.003));
} else if(raceRound == 2){
// final lap
float d = finallap(p);
col = mix(col,vec3(1.),S(d));
col = mix(col,vec3(0.),S(abs(d)-0.003));
} else if(raceRound == 3){
// goal
float d = goal(p);
col = mix(col,vec3(1.),S(d));
col = mix(col,vec3(0.),S(abs(d)-0.003));
}
// render ui
col = ui(p-vec2(initialUiX,0.0),col);
return col;
}
void main( void ){
vec2 p = (gl_FragCoord.xy-.5*resolution.xy)/resolution.y;
vec3 col = vec3(0.0);
col = drawRaceScene(p,col);
fragColor = vec4(vec3(col), 1.0);
}