mirror of
https://github.com/libretro/slang-shaders.git
synced 2024-11-23 00:10:03 +00:00
337 lines
8.3 KiB
Plaintext
337 lines
8.3 KiB
Plaintext
#version 450
|
|
// Stairway to the Stars - dr2 - 2015-05-13
|
|
// https://www.shadertoy.com/view/lls3z7
|
|
|
|
// A long climb; use the mouse to look around.
|
|
|
|
// "Stairway to the Stars" by dr2 - 2015
|
|
// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
|
|
|
|
layout(std140, set = 0, binding = 0) uniform UBO
|
|
{
|
|
mat4 MVP;
|
|
vec4 OutputSize;
|
|
vec4 OriginalSize;
|
|
vec4 SourceSize;
|
|
uint FrameCount;
|
|
} global;
|
|
|
|
#pragma stage vertex
|
|
layout(location = 0) in vec4 Position;
|
|
layout(location = 1) in vec2 TexCoord;
|
|
layout(location = 0) out vec2 vTexCoord;
|
|
const vec2 madd = vec2(0.5, 0.5);
|
|
void main()
|
|
{
|
|
gl_Position = global.MVP * Position;
|
|
vTexCoord = gl_Position.xy;
|
|
}
|
|
|
|
#pragma stage fragment
|
|
layout(location = 0) in vec2 vTexCoord;
|
|
layout(location = 0) out vec4 FragColor;
|
|
float iGlobalTime = float(global.FrameCount)*0.025;
|
|
vec2 iResolution = global.OutputSize.xy;
|
|
|
|
const float pi = 3.14159;
|
|
const vec4 cHashA4 = vec4 (0., 1., 57., 58.);
|
|
const vec3 cHashA3 = vec3 (1., 57., 113.);
|
|
const float cHashM = 43758.54;
|
|
|
|
vec4 Hashv4f (float p)
|
|
{
|
|
return fract (sin (p + cHashA4) * cHashM);
|
|
}
|
|
|
|
float Noisefv2 (vec2 p)
|
|
{
|
|
vec2 i = floor (p);
|
|
vec2 f = fract (p);
|
|
f = f * f * (3. - 2. * f);
|
|
vec4 t = Hashv4f (dot (i, cHashA3.xy));
|
|
return mix (mix (t.x, t.y, f.x), mix (t.z, t.w, f.x), f.y);
|
|
}
|
|
|
|
float Fbm2 (vec2 p)
|
|
{
|
|
float s = 0.;
|
|
float a = 1.;
|
|
for (int i = 0; i < 5; i ++) {
|
|
s += a * Noisefv2 (p);
|
|
a *= 0.5;
|
|
p *= 2.;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
float PrSphDf (vec3 p, float s)
|
|
{
|
|
return length (p) - s;
|
|
}
|
|
|
|
vec2 Rot2D (vec2 q, float a)
|
|
{
|
|
return q * cos (a) * vec2 (1., 1.) + q.yx * sin (a) * vec2 (-1., 1.);
|
|
}
|
|
|
|
#define REFBALL
|
|
|
|
int idObj;
|
|
float tCur, stPitch, rotAng, rOut, rIn, rWid;
|
|
vec3 qHit, ltPos[2];
|
|
int doLt;
|
|
const float dstFar = 20.;
|
|
|
|
vec3 BrickCol (vec2 p)
|
|
{
|
|
vec2 i = floor (p);
|
|
if (2. * floor (i.y / 2.) != i.y) {
|
|
p.x += 0.5;
|
|
i = floor (p);
|
|
}
|
|
p = smoothstep (0.02, 0.08, abs (fract (p + 0.5) - 0.5));
|
|
return (0.5 + 0.5 * p.x * p.y) * vec3 (0.5, 0.4, 0.3);
|
|
}
|
|
|
|
vec3 WoodCol (vec2 p)
|
|
{
|
|
float f = Fbm2 (p * vec2 (1., 0.1));
|
|
return mix (vec3 (0.8, 0.4, 0.2), vec3 (0.45, 0.25, 0.1), f);
|
|
}
|
|
|
|
float ObjDf (vec3 p)
|
|
{
|
|
vec3 q, pp;
|
|
float d, dr, da, dy, dMin, r, ns, nh, sh, sw, rw, ca, sa;
|
|
const int ins = 12;
|
|
const int inh = 6;
|
|
dMin = dstFar;
|
|
ns = float (ins);
|
|
nh = float (inh);
|
|
sh = 0.2 * stPitch / ns;
|
|
sw = 1.1 * pi * rOut / ns;
|
|
rw = 0.09;
|
|
pp = p;
|
|
pp.xz = Rot2D (pp.xz, rotAng);
|
|
pp.y += stPitch * rotAng / (2. * pi);
|
|
r = length (pp.xz);
|
|
dr = max (r - rOut, rIn - r);
|
|
q = pp;
|
|
d = dMin;
|
|
dy = stPitch / ns;
|
|
q.y -= dy;
|
|
da = 2. * pi / ns;
|
|
ca = cos (da); sa = sin (da);
|
|
for (int j = 0; j < ins; j ++) {
|
|
q.y = mod (q.y + dy + 0.5 * stPitch, stPitch) - 0.5 * stPitch;
|
|
d = min (d, max (max (max (dr, abs (q.z) - sw), q.x), abs (q.y) - sh));
|
|
if (d < dMin) { dMin = d; idObj = 1; qHit = q; }
|
|
q.xz = q.xz * ca + q.zx * vec2 (- sa, sa);
|
|
}
|
|
d = min (min (d, max (r - rIn, - (r - rIn + rWid))),
|
|
max (r - rOut - rWid, - (r - rOut)));
|
|
q = pp;
|
|
dy = stPitch / nh;
|
|
q.y -= 0.25 * stPitch + dy;
|
|
da = 2. * pi / nh;
|
|
ca = cos (da); sa = sin (da);
|
|
for (int j = 0; j < inh; j ++) {
|
|
q.y = mod (q.y + dy + 0.5 * stPitch, stPitch) - 0.5 * stPitch;
|
|
d = max (d, - length (q.xy) + rw);
|
|
q.xz = q.xz * ca + q.zx * vec2 (- sa, sa);
|
|
}
|
|
if (d < dMin) { dMin = d; idObj = 2; qHit = q; }
|
|
if (doLt != 0) {
|
|
d = PrSphDf (p - ltPos[0], 0.07 * rIn);
|
|
if (d < dMin) { dMin = d; idObj = 5; }
|
|
}
|
|
if (doLt != 1) {
|
|
d = PrSphDf (p - ltPos[1], 0.07 * rIn);
|
|
if (d < dMin) { dMin = d; idObj = 6; }
|
|
}
|
|
#ifdef REFBALL
|
|
d = min (d, max (r - 0.006 * rIn, 0.));
|
|
if (d < dMin) { dMin = d; idObj = 3; }
|
|
pp = p;
|
|
pp.y = mod (pp.y + stPitch * rotAng / (2. * pi) + 0.5 * stPitch, stPitch) -
|
|
0.5 * stPitch;
|
|
d = PrSphDf (pp, 0.3 * rIn);
|
|
if (d < dMin) { dMin = d; idObj = 4; }
|
|
#endif
|
|
return dMin;
|
|
}
|
|
|
|
vec3 ObjNf (vec3 p)
|
|
{
|
|
const vec3 e = vec3 (0.001, -0.001, 0.);
|
|
vec4 v = vec4 (ObjDf (p + e.xxx), ObjDf (p + e.xyy),
|
|
ObjDf (p + e.yxy), ObjDf (p + e.yyx));
|
|
return normalize (vec3 (v.x - v.y - v.z - v.w) + 2. * vec3 (v.y, v.z, v.w));
|
|
}
|
|
|
|
float ObjRay (vec3 ro, vec3 rd)
|
|
{
|
|
float dHit, d;
|
|
dHit = 0.;
|
|
for (int j = 0; j < 100; j ++) {
|
|
d = ObjDf (ro + dHit * rd);
|
|
dHit += d;
|
|
if (d < 0.001 || dHit > dstFar) break;
|
|
}
|
|
return dHit;
|
|
}
|
|
|
|
vec3 ObjCol (vec3 ro, vec3 rd, vec3 vn)
|
|
{
|
|
vec3 ltDir, acDif, col;
|
|
float ltDist, ltDistSq, dif, atten, acSpe, sh, d, h;
|
|
col = vec3 (0.);
|
|
if (idObj == 1) {
|
|
col = WoodCol (120. * qHit.zx);
|
|
} else if (idObj == 2) {
|
|
if (abs (vn.y) > 0.005) col = 0.4 * vec3 (0.5, 0.4, 0.3);
|
|
else col = BrickCol (vec2 (20. * (atan (qHit.z, qHit.x) / pi + 1.),
|
|
40. * qHit.y));
|
|
} else if (idObj == 3) {
|
|
col = vec3 (0.4, 0.4, 0.2);
|
|
} else if (idObj == 5) {
|
|
col = vec3 (1., 1., 0.5) * (0.75 + 0.25 * dot (rd, normalize (ltPos[0] - ro)));
|
|
} else if (idObj == 6) {
|
|
col = vec3 (1., 1., 0.5) * (0.75 + 0.25 * dot (rd, normalize (ltPos[1] - ro)));
|
|
}
|
|
if (idObj < 5) {
|
|
acDif = vec3 (0.);
|
|
acSpe = 0.;
|
|
for (int j = 0; j < 2; j ++) {
|
|
doLt = j;
|
|
ltDir = ltPos[j] - ro;
|
|
ltDistSq = dot (ltDir, ltDir);
|
|
ltDist = sqrt (ltDistSq);
|
|
ltDir /= ltDist;
|
|
dif = clamp (dot (vn, ltDir), 0., 1.);
|
|
sh = 0.;
|
|
if (dif > 0.) {
|
|
sh = 1.;
|
|
d = 0.01;
|
|
for (int i = 0; i < 60; i ++) {
|
|
h = ObjDf (ro + ltDir * d);
|
|
sh = min (sh, 50. * h / d);
|
|
d += h;
|
|
if (d > ltDist) break;
|
|
}
|
|
dif *= sh;
|
|
}
|
|
atten = 1. / (0.1 + ltDistSq);
|
|
acDif += atten * dif;
|
|
acSpe += atten * sh * pow (clamp (dot (reflect (rd, vn), ltDir), 0., 1.), 16.);
|
|
}
|
|
col = (0.4 + 0.2 * acDif) * col + 0.03 * acSpe * vec3 (1.);
|
|
}
|
|
return col;
|
|
}
|
|
|
|
float GlowCol (vec3 ro, vec3 rd, float dstHit)
|
|
{
|
|
vec3 ltDir;
|
|
float ltDist, wGlow;
|
|
wGlow = 0.;
|
|
for (int j = 0; j < 2; j ++) {
|
|
ltDir = ltPos[j] - ro;
|
|
ltDist = length (ltDir);
|
|
ltDir /= ltDist;
|
|
if (ltDist < dstHit) wGlow += pow (max (dot (rd, ltDir), 0.), 1024.) / ltDist;
|
|
}
|
|
return clamp (0.5 * wGlow, 0., 1.);
|
|
}
|
|
|
|
vec3 ShowScene (vec3 ro, vec3 rd)
|
|
{
|
|
vec3 col, vn, roo, rds;
|
|
float dstHit, rLt, aLt;
|
|
int idObjT;
|
|
rotAng = 0.3 * tCur;
|
|
stPitch = 0.4;
|
|
rWid = 0.006;
|
|
rLt = 0.6 * rOut;
|
|
aLt = 0.1 * pi;
|
|
ltPos[0] = vec3 (rLt * cos (aLt), stPitch * (0.1 - 0.14 * cos (tCur)),
|
|
rLt * sin (aLt));
|
|
aLt = - 0.95 * pi;
|
|
ltPos[1] = vec3 (rLt * cos (aLt), stPitch * (-0.4 + 0.14 * sin (tCur)),
|
|
rLt * sin (aLt));
|
|
roo = ro;
|
|
idObj = -1;
|
|
doLt = -1;
|
|
dstHit = ObjRay (ro, rd);
|
|
if (idObj < 0) dstHit = dstFar;
|
|
#ifdef REFBALL
|
|
if (idObj == 4 && dstHit < dstFar) {
|
|
ro += rd * dstHit;
|
|
rd = reflect (rd, ObjNf (ro));
|
|
ro += 0.01 * rd;
|
|
roo = ro;
|
|
idObj = -1;
|
|
dstHit = ObjRay (ro, rd);
|
|
}
|
|
#endif
|
|
if (dstHit >= dstFar) {
|
|
col = vec3 (0., 0., 0.1);
|
|
rds = rd;
|
|
rds.xz = Rot2D (rds.xz, rotAng);
|
|
rds = (rds + vec3 (1.));
|
|
for (int j = 0; j < 10; j ++)
|
|
rds = 11. * abs (rds) / dot (rds, rds) - 3.;
|
|
col += min (1., 1.5e-6 * pow (min (16., length (rds)), 5.)) *
|
|
vec3 (0.7, 0.6, 0.6);
|
|
} else {
|
|
ro += rd * dstHit;
|
|
idObjT = idObj;
|
|
vn = ObjNf (ro);
|
|
idObj = idObjT;
|
|
col = ObjCol (ro, rd, vn);
|
|
}
|
|
col = mix (col, vec3 (1., 1., 0.5), GlowCol (roo, rd, dstHit));
|
|
return clamp (col, 0., 1.);
|
|
}
|
|
|
|
void mainImage (out vec4 fragColor, in vec2 fragCoord)
|
|
{
|
|
vec2 canvas = iResolution.xy;
|
|
vec2 uv = 2. * fragCoord.xy / canvas - 1.;
|
|
uv.x *= canvas.x / canvas.y;
|
|
tCur = iGlobalTime;
|
|
#ifdef MOUSE
|
|
vec4 mPtr = iMouse;
|
|
mPtr.xy = mPtr.xy / canvas - 0.5;
|
|
#endif
|
|
mat3 vuMat;
|
|
vec3 ro, rd;
|
|
vec2 vEl, vAz;
|
|
float az, el;
|
|
rOut = 0.5;
|
|
rIn = 0.2;
|
|
ro = - vec3 (0., 0.1, 0.9) * rOut;
|
|
az = 0.2;
|
|
el = 0.1;
|
|
#ifdef MOUSE
|
|
if (mPtr.z > 0.) {
|
|
ro.z = clamp (ro.z + 0.8 * mPtr.x, - 0.99 * rOut, - 0.4 * rIn);
|
|
el = clamp (el + 3. * mPtr.y, -1.5, 1.5);
|
|
}
|
|
#endif
|
|
vEl = vec2 (cos (el), sin (el));
|
|
vAz = vec2 (cos (az), sin (az));
|
|
vuMat = mat3 (1., 0., 0., 0., vEl.x, - vEl.y, 0., vEl.y, vEl.x) *
|
|
mat3 (vAz.x, 0., vAz.y, 0., 1., 0., - vAz.y, 0., vAz.x);
|
|
rd = normalize (vec3 (uv, 1.5)) * vuMat;
|
|
fragColor = vec4 (ShowScene (ro, rd), 1.);
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
//just some shit to wrap shadertoy's stuff
|
|
vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy;
|
|
FragmentCoord.y = -FragmentCoord.y;
|
|
mainImage(FragColor,FragmentCoord);
|
|
}
|