281 lines
8.1 KiB
GLSL
281 lines
8.1 KiB
GLSL
const float epsilon = 0.02;
|
|
const float pi = 3.14159265359;
|
|
const float speed = 3.0;
|
|
const vec3 wallsColor = vec3(0.05, 0.025, 0.025);
|
|
const vec3 lightColor = vec3(0.3, 0.6, 1.0);
|
|
const vec3 lightColor2 = vec3(0.5, 0.35, 0.35);
|
|
const vec3 fogColor = vec3(0.05, 0.05, 0.2);
|
|
const float curvAmout = 0.075;
|
|
const float reflAmout = 0.8;
|
|
|
|
//Distance Field functions by iq :
|
|
//https://iquilezles.org/articles/distfunctions
|
|
float sdCylinder( vec3 p, vec3 c )
|
|
{
|
|
return length(c.xy - p.xz) - c.z;
|
|
}
|
|
|
|
float sdCappedCylinder( vec3 p, vec2 h )
|
|
{
|
|
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
|
|
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
|
|
}
|
|
|
|
float sdSphere( vec3 p, float s )
|
|
{
|
|
return length(p)-s;
|
|
}
|
|
|
|
float sdBox( vec3 p, vec3 b )
|
|
{
|
|
vec3 d = abs(p) - b;
|
|
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
|
|
}
|
|
|
|
vec3 opRep( vec3 p, vec3 c )
|
|
{
|
|
return mod(p,c)-0.5*c;
|
|
}
|
|
|
|
vec2 linearStep2(vec2 mi, vec2 ma, vec2 v)
|
|
{
|
|
return clamp((v - mi) / (ma - mi), 0.0 ,1.0);
|
|
}
|
|
|
|
float tunnel( vec3 p, vec3 c )
|
|
{
|
|
return -length(c.xy - p.xz) + c.z;
|
|
}
|
|
|
|
vec4 distfunc(vec3 pos)
|
|
{
|
|
vec3 repPos = opRep(pos, vec3(4.0, 1.0, 4.0));
|
|
vec2 sinPos = sin((pos.z * pi / 8.0) + vec2(0.0, pi)) * 1.75;
|
|
vec3 repPosSin = opRep(pos.xxz + vec3(sinPos.x, sinPos.y, 0.0), vec3(4.0, 4.0, 0.0));
|
|
|
|
float cylinders = sdCylinder(vec3(repPos.x, pos.y, repPos.z), vec3(0.0, 0.0, 0.5));
|
|
float s = sin(iTime*3.0 + floor(pos.z*0.25));
|
|
float cutCylinders1 = sdBox(vec3(pos.x, pos.y, repPos.z), vec3(100.0, clamp(s, 0.025, 0.75), 1.0));
|
|
float cutCylinders2 = sdBox(vec3(repPos.x, pos.y, repPos.z), vec3(0.035, 100.0, 10.0));
|
|
float cuttedCylinders = max(-cutCylinders2, max(-cutCylinders1, cylinders));
|
|
|
|
float innerCylinders = sdCylinder(vec3(repPos.x, pos.y, repPos.z), vec3(0.0, 0.0, 0.15));
|
|
float tubes1 = sdCylinder(vec3(repPosSin.x, 0.0, pos.y - 0.85), vec3(0.0, 0.0, 0.025));
|
|
float tubes2 = sdCylinder(vec3(repPosSin.y, 0.0, pos.y + 0.85), vec3(0.0, 0.0, 0.025));
|
|
float tubes = min(tubes1, tubes2);
|
|
float lightsGeom = min(tubes, innerCylinders);
|
|
|
|
float resultCylinders = min(cuttedCylinders, lightsGeom);
|
|
|
|
float spheres = sdSphere(vec3(repPos.x, pos.y, repPos.z), (s*0.5+0.5)*1.5);
|
|
float light = min(tubes, spheres);
|
|
|
|
vec2 planeMod = abs(fract(pos.xx * vec2(0.25, 4.0) + 0.5) * 4.0 - 2.0) - 1.0;
|
|
float planeMod2 = clamp(planeMod.y, -0.02, 0.02) * min(0.0, planeMod.x);
|
|
float cylindersCutPlane = sdCylinder(vec3(repPos.x, pos.y, repPos.z), vec3(0.0, 0.0, 0.6));
|
|
float spheresCutPlane = sdSphere(vec3(repPos.x, pos.y, repPos.z), 1.3);
|
|
|
|
float plane = 1.0 - abs(pos.y + clamp(planeMod.x, -0.04, 0.04) + planeMod2);
|
|
float t = tunnel(pos.xzy * vec3(1.0, 1.0, 3.0), vec3(0.0, 0.0, 8.5));
|
|
float cutTunnel = sdBox(vec3(pos.x, pos.y, repPos.z), vec3(100.0, 100.0, 0.1));
|
|
plane = min(max(-cutTunnel, t), max(-spheresCutPlane, max(-cylindersCutPlane, plane)));
|
|
|
|
float dist = min(resultCylinders, plane);
|
|
float occ = min(cuttedCylinders, plane);
|
|
|
|
float id = 0.0;
|
|
|
|
if(lightsGeom < epsilon)
|
|
{
|
|
id = 1.0;
|
|
}
|
|
|
|
return vec4(dist, id, light, occ);
|
|
}
|
|
|
|
vec3 rayMarch(vec3 rayDir, vec3 cameraOrigin)
|
|
{
|
|
const int maxItter = 100;
|
|
const float maxDist = 30.0;
|
|
|
|
float totalDist = 0.0;
|
|
vec3 pos = cameraOrigin;
|
|
vec4 dist = vec4(epsilon);
|
|
|
|
for(int i = 0; i < maxItter; i++)
|
|
{
|
|
dist = distfunc(pos);
|
|
totalDist += dist.x;
|
|
pos += dist.x * rayDir;
|
|
|
|
if(dist.x < epsilon || totalDist > maxDist)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return vec3(dist.x, totalDist, dist.y);
|
|
}
|
|
|
|
vec3 rayMarchReflection(vec3 rayDir, vec3 cameraOrigin)
|
|
{
|
|
const int maxItter = 30;
|
|
const float maxDist = 20.0;
|
|
|
|
float totalDist = 0.0;
|
|
vec3 pos = cameraOrigin;
|
|
vec4 dist = vec4(epsilon);
|
|
|
|
for(int i = 0; i < maxItter; i++)
|
|
{
|
|
dist = distfunc(pos);
|
|
totalDist += dist.x;
|
|
pos += dist.x * rayDir;
|
|
|
|
if(dist.x < epsilon || totalDist > maxDist)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return vec3(dist.x, totalDist, dist.y);
|
|
}
|
|
|
|
//Inpired From iq's ao :
|
|
//https://www.shadertoy.com/view/Xds3zN
|
|
vec2 AOandFakeAreaLights(vec3 pos, vec3 n)
|
|
{
|
|
vec4 res = vec4(0.0);
|
|
|
|
for( int i=0; i<3; i++ )
|
|
{
|
|
vec3 aopos = pos + n*0.3*float(i);
|
|
vec4 d = distfunc(aopos);
|
|
res += d;
|
|
}
|
|
|
|
float ao = clamp(res.w, 0.0, 1.0);
|
|
float light = 1.0 - clamp(res.z*0.3, 0.0, 1.0);
|
|
|
|
return vec2(ao, light * ao);
|
|
}
|
|
|
|
//Camera Function by iq :
|
|
//https://www.shadertoy.com/view/Xds3zN
|
|
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
|
|
{
|
|
vec3 cw = normalize(ta-ro);
|
|
vec3 cp = vec3(sin(cr), cos(cr),0.0);
|
|
vec3 cu = normalize( cross(cw,cp) );
|
|
vec3 cv = normalize( cross(cu,cw) );
|
|
return mat3( cu, cv, cw );
|
|
}
|
|
|
|
//Normal and Curvature Function by Nimitz;
|
|
//https://www.shadertoy.com/view/Xts3WM
|
|
vec4 norcurv(in vec3 p)
|
|
{
|
|
vec2 e = vec2(-epsilon, epsilon);
|
|
float t1 = distfunc(p + e.yxx).x, t2 = distfunc(p + e.xxy).x;
|
|
float t3 = distfunc(p + e.xyx).x, t4 = distfunc(p + e.yyy).x;
|
|
|
|
float curv = .25/e.y*(t1 + t2 + t3 + t4 - 4.0 * distfunc(p).x);
|
|
return vec4(normalize(e.yxx*t1 + e.xxy*t2 + e.xyx*t3 + e.yyy*t4), curv);
|
|
}
|
|
|
|
vec4 lighting(vec3 n, vec3 rayDir, vec3 reflectDir, vec3 pos)
|
|
{
|
|
vec3 light = vec3(0.0, 0.0, 2.0 + iTime * speed);
|
|
vec3 lightVec = light - pos;
|
|
vec3 lightDir = normalize(lightVec);
|
|
float atten = clamp(1.0 - length(lightVec)*0.1, 0.0, 1.0);
|
|
float spec = pow(max(0.0, dot(reflectDir, lightDir)), 10.0);
|
|
float rim = (1.0 - max(0.0, dot(-n, rayDir)));
|
|
|
|
return vec4(spec*atten*lightColor2 + rim*0.2, rim);
|
|
}
|
|
|
|
vec3 color(float id, vec3 pos)
|
|
{
|
|
vec2 fp = vec2(1.0) - linearStep2(vec2(0.0), vec2(0.01), abs(fract(pos.xz * vec2(0.25, 1.0) + vec2(0.0, 0.5)) - 0.5));
|
|
float s = fp.y + fp.x;
|
|
return mix(wallsColor + s*lightColor*0.5, lightColor, id);
|
|
}
|
|
|
|
vec4 finalColor(vec3 rayDir, vec3 reflectDir, vec3 pos, vec3 normal, float ao, float id)
|
|
{
|
|
vec4 l = lighting(normal, rayDir, reflectDir, pos);
|
|
vec3 col = color(id, pos);
|
|
float ao1 = 0.5 * ao + 0.5;
|
|
float ao2 = 0.25 * ao + 0.75;
|
|
vec3 res = (mix(col * ao1, col, id) + l.xyz) * ao2;
|
|
return vec4(res, l.w);
|
|
}
|
|
|
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
|
{
|
|
vec2 uv = fragCoord.xy/iResolution.xy;
|
|
|
|
float move = iTime * speed;
|
|
vec2 sinMove = sin((move * pi) / 16.0 + vec2(1.0, -1.0)) * vec2(5.0, 0.35);
|
|
float camX = sinMove.x;
|
|
float camY = 0.0;
|
|
float camZ = -5.0 + move;
|
|
vec3 cameraOrigin = vec3(camX, camY, camZ);
|
|
|
|
vec3 cameraTarget = vec3(0.0, 0.0, cameraOrigin.z + 10.0);
|
|
|
|
vec2 screenPos = uv * 2.0 - 1.0;
|
|
|
|
screenPos.x *= iResolution.x/iResolution.y;
|
|
|
|
mat3 cam = setCamera(cameraOrigin, cameraTarget, sinMove.y);
|
|
|
|
vec3 rayDir = cam*normalize(vec3(screenPos.xy,1.0));
|
|
vec3 dist = rayMarch(rayDir, cameraOrigin);
|
|
|
|
vec3 res;
|
|
vec2 fog;
|
|
|
|
if(dist.x < epsilon)
|
|
{
|
|
vec3 pos = cameraOrigin + dist.y*rayDir;
|
|
vec4 n = norcurv(pos);
|
|
vec2 ao = AOandFakeAreaLights(pos, n.xyz);
|
|
vec3 r = reflect(rayDir, n.xyz);
|
|
vec3 rpos = pos + n.xyz*0.02;
|
|
vec3 reflectDist = rayMarchReflection(r, rpos);
|
|
fog = clamp(1.0 / exp(vec2(dist.y, reflectDist.y)*vec2(0.15, 0.2)), 0.0, 1.0);
|
|
vec4 direct = finalColor(rayDir, r, pos, n.xyz, ao.x, dist.z) + n.w*curvAmout;
|
|
|
|
vec4 reflN;
|
|
vec2 reflAO;
|
|
vec3 reflFinal;
|
|
|
|
if(reflectDist.x < epsilon)
|
|
{
|
|
vec3 reflPos = rpos + reflectDist.y*r;
|
|
reflN = norcurv(reflPos);
|
|
reflAO = AOandFakeAreaLights(reflPos, reflN.xyz);
|
|
vec3 rr = reflect(r, reflN.xyz);
|
|
vec4 refl = finalColor(r, rr, reflPos, reflN.xyz, reflAO.x, reflectDist.z);
|
|
vec3 reflAreaLights = reflAO.y * lightColor * 0.5;
|
|
reflFinal = (refl.xyz + reflN.w*curvAmout + reflAreaLights) * fog.y * reflAmout * direct.w;
|
|
}
|
|
else
|
|
{
|
|
reflFinal = vec3(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
vec3 areaLightsColor = ao.y * lightColor * 0.5;
|
|
|
|
res = mix(fogColor, direct.xyz + reflFinal + areaLightsColor, fog.x);
|
|
}
|
|
else
|
|
{
|
|
res = fogColor;
|
|
fog = vec2(0.0);
|
|
}
|
|
|
|
fragColor = vec4(res, (dist.z) * fog);
|
|
} |