mirror of
https://github.com/libretro/slang-shaders.git
synced 2024-11-27 02:20:41 +00:00
333 lines
8.7 KiB
Plaintext
333 lines
8.7 KiB
Plaintext
#version 450
|
|
// Cave Quest - Bergi - 2016-06-25
|
|
// https://www.shadertoy.com/view/XdGXD3
|
|
|
|
// Lot's of finetuning to get a nice cave fly-through.
|
|
// Greetings to Kali and Shane
|
|
|
|
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;
|
|
|
|
/** Cave Quest
|
|
https://www.shadertoy.com/view/XdGXD3
|
|
|
|
(cc) 2016, stefan berke
|
|
|
|
Based on "Kali Trace" https://www.shadertoy.com/view/4sKXWG
|
|
|
|
Interesting things here might be:
|
|
- the distance formula in itself
|
|
- wrapping 3d-space using sin() for endless kali-set patterns
|
|
- kali-set used for normals, micro-normals and texturing
|
|
- epsilon in normal estimation for artistic tuning
|
|
|
|
*/
|
|
|
|
|
|
// minimum distance to axis-aligned planes in kali-space
|
|
// uses eiffie's mod (/p.w) https://www.shadertoy.com/view/XtlGRj
|
|
// to keep the result close to a true distance function
|
|
vec3 kali_set(in vec3 pos, in vec3 param)
|
|
{
|
|
vec4 p = vec4(pos, 1.);
|
|
vec3 d = vec3(100.);
|
|
for (int i=0; i<9; ++i)
|
|
{
|
|
p = abs(p) / dot(p.xyz,p.xyz);
|
|
d = min(d, p.xyz/p.w);
|
|
p.xyz = p.zxy - param;
|
|
}
|
|
return d;
|
|
}
|
|
|
|
// average of all iterations in kali-set
|
|
vec3 kali_set_av(in vec3 p, in vec3 param)
|
|
{
|
|
vec3 d = vec3(0.);
|
|
for (int i=0; i<13; ++i)
|
|
{
|
|
p = abs(p) / dot(p,p);
|
|
d += exp(-p*8.);
|
|
p.xyz = p.zxy - param;
|
|
}
|
|
return d / 8.;
|
|
}
|
|
|
|
// endless texture
|
|
vec3 kali_tex(in vec3 p, in vec3 par)
|
|
{
|
|
vec3 k = kali_set_av(sin(p*3.)*.3, par);
|
|
return 3.*k;
|
|
}
|
|
|
|
// endless texture normal
|
|
vec3 kali_tex_norm(in vec3 p, in vec3 param, vec3 mask, float eps)
|
|
{
|
|
vec2 e = vec2(eps, 0.);
|
|
return normalize(vec3(
|
|
dot(kali_tex(p+e.xyy, param),mask) - dot(kali_tex(p-e.xyy, param),mask),
|
|
dot(kali_tex(p+e.yxy, param),mask) - dot(kali_tex(p-e.yxy, param),mask),
|
|
dot(kali_tex(p+e.yyx, param),mask) - dot(kali_tex(p-e.yyx, param),mask)));
|
|
}
|
|
|
|
|
|
|
|
// camera path
|
|
vec3 path(in float z)
|
|
{
|
|
float t = z;
|
|
vec3 p = vec3(sin(t)*.5,
|
|
.26*sin(t*3.16),
|
|
z);
|
|
return p;
|
|
}
|
|
|
|
|
|
float DE(in vec3 p, in vec3 param)
|
|
{
|
|
// tube around path
|
|
float r = .13+.1*sin(p.z*.89);
|
|
vec3 pp = p - path(p.z); float d = r-max(abs(pp.x), abs(pp.y));
|
|
|
|
// displacement
|
|
vec3 k = kali_set(sin(p), param);
|
|
d += k.x+k.y+k.z;
|
|
//d += max(k.x,max(k.y,k.z));
|
|
//d += min(k.x,min(k.y,k.z));
|
|
return d;
|
|
}
|
|
|
|
vec3 DE_norm(in vec3 p, in vec3 param, in float eps)
|
|
{
|
|
vec2 e = vec2(eps, 0.);
|
|
return normalize(vec3(
|
|
DE(p+e.xyy, param) - DE(p-e.xyy, param),
|
|
DE(p+e.yxy, param) - DE(p-e.yxy, param),
|
|
DE(p+e.yyx, param) - DE(p-e.yyx, param)));
|
|
}
|
|
|
|
|
|
// lighting/shading currently depends on this beeing 1.
|
|
const float max_t = 1.;
|
|
|
|
// common sphere tracing
|
|
// note the check against abs(d) to get closer to surface
|
|
// in case of overstepping
|
|
float trace(in vec3 ro, in vec3 rd, in vec3 param)
|
|
{
|
|
float t = 0.001, d = max_t;
|
|
for (int i=0; i<50; ++i)
|
|
{
|
|
vec3 p = ro + rd * t;
|
|
d = DE(p, param);
|
|
if (abs(d) <= 0.00001 || t >= max_t)
|
|
break;
|
|
t += d * .5; // above kali-distance still needs a lot of fudging
|
|
}
|
|
return t;
|
|
}
|
|
|
|
// "Enhanced Sphere Tracing"
|
|
// Benjamin Keinert(1) Henry Schäfer(1) Johann Korndörfer Urs Ganse(2) Marc Stamminger(1)
|
|
// 1 University of Erlangen-Nuremberg, 2 University of Helsinki
|
|
//
|
|
// It was a try... disabled by default (see rayColor() below)
|
|
// Just here for experimentation
|
|
// Obviously the algorithm does not like "fudging" which is needed for my distance field..
|
|
// It renders more stuff close to edges but creates a lot of artifacts elsewhere
|
|
float trace_enhanced(in vec3 ro, in vec3 rd, in vec3 param)
|
|
{
|
|
float omega = 1.2; // overstepping
|
|
float t = 0.001;
|
|
float candidate_error = 100000.;
|
|
float candidate_t = t;
|
|
float previousRadius = 0.;
|
|
float stepLength = .0;
|
|
float signedRadius;
|
|
float pixelRadius = .012;
|
|
float fudge = 0.6;
|
|
for (int i = 0; i < 50; ++i)
|
|
{
|
|
signedRadius = DE(rd*t + ro, param);
|
|
float radius = abs(signedRadius);
|
|
bool sorFail = omega > 1. && (radius + previousRadius) < stepLength;
|
|
if (sorFail)
|
|
{
|
|
stepLength -= omega * stepLength;
|
|
omega = 1.;
|
|
}
|
|
else
|
|
{
|
|
stepLength = signedRadius * omega;
|
|
}
|
|
previousRadius = radius;
|
|
float error = radius / t;
|
|
if (!sorFail && error < candidate_error)
|
|
{
|
|
candidate_t = t;
|
|
candidate_error = error;
|
|
}
|
|
if (!sorFail && error < pixelRadius || t > max_t)
|
|
break;
|
|
t += stepLength * fudge;
|
|
}
|
|
return (t > max_t || candidate_error > pixelRadius)
|
|
? max_t : candidate_t;
|
|
}
|
|
|
|
// common ambient occlusion
|
|
float traceAO(in vec3 ro, in vec3 rd, in vec3 param)
|
|
{
|
|
float a = 0., t = 0.01;
|
|
for (int i=0; i<5; ++i)
|
|
{
|
|
float d = DE(ro+t*rd, param);
|
|
a += d / t;
|
|
t += abs(d);
|
|
}
|
|
return clamp(a / 8., 0., 1.);
|
|
}
|
|
|
|
// environment map, also drawn from kaliset
|
|
vec3 skyColor(in vec3 rd)
|
|
{
|
|
//vec3 par = vec3(0.075, 0.565, .03);
|
|
vec3 par = vec3(.9, .81, .71);
|
|
|
|
vec3 c = kali_set(sin(rd*6.), par);
|
|
c = pow(min(vec3(1.), c*2.+vec3(1.,.86,.6)), 1.+114.*c);
|
|
|
|
return clamp(c, 0., 1.);
|
|
}
|
|
|
|
|
|
// trace and color
|
|
vec3 rayColor(in vec3 ro, in vec3 rd)
|
|
{
|
|
// magic params for kali-set
|
|
vec3 par1 = vec3(.9, .6+.5*sin(ro.z/50.), 1.), // scene geometry
|
|
par2 = vec3(.63, .55, .73), // normal/bump map
|
|
par3 = vec3(1.02, 0.82, 0.77); // normal/texture
|
|
|
|
#if 1
|
|
float t = trace(ro, rd, par1);
|
|
#else
|
|
float t = trace_enhanced(ro, rd, par1);
|
|
#endif
|
|
vec3 p = ro + t * rd;
|
|
float d = DE(p, par1);
|
|
|
|
vec3 col = vec3(0.);
|
|
|
|
// did ray hit?
|
|
if (d < 0.03)
|
|
{
|
|
float scr_eps = max(0.001, (t-0.1)*0.025);
|
|
// "some" texture values
|
|
vec3 kt = kali_tex(p, par3);
|
|
// surface normal
|
|
vec3 n = DE_norm(p, par1, 0.5*scr_eps), nn = n;
|
|
// normal displacement
|
|
n = normalize(n + 0.3*kali_tex_norm(p, par3+0.1*n, vec3(1), scr_eps));
|
|
n = normalize(n + 0.3*DE_norm(sin(n*3.+kt), par2, 2.*scr_eps)); // micro-bumps
|
|
// reflected ray
|
|
vec3 rrd = reflect(rd,n);
|
|
// normal towards light
|
|
vec3 ln = normalize(path(p.z+.1) - p);
|
|
// 1. - occlusion
|
|
float ao = pow(traceAO(p, n, par1), 1.+3.*t);
|
|
// surface color
|
|
vec3 col1 = .45 * (vec3(.7,1.,.4) + kali_tex(p, par3));
|
|
vec3 col2 = vec3(1.,.8,.6) + .3 * vec3(1.,.7,-.6) * kali_tex(p, par3);
|
|
vec3 k = kali_set_av(sin(p*(1.+3.*ao))*.3, par3);
|
|
vec3 surf = (.1 + .9 * ao)
|
|
//* vec3(1.);
|
|
* mix(col1, col2, min(1., pow(ao*2.2-.8*kt.x,5.)));
|
|
// desaturate
|
|
surf += .24 * (dot(surf,vec3(.3,.6,.1)) - surf);
|
|
|
|
// -- lighting --
|
|
|
|
float fres = pow(max(0., 1.-dot(rrd, n)), 1.) / (1.+2.*t);
|
|
|
|
// phong
|
|
surf += .25 * ao * max(0., dot(n, ln));
|
|
// spec
|
|
float d = max(0., dot(rrd, ln));
|
|
surf += .4 * pow(ao*1.2,5.) * (.5 * d + .7 * pow(d, 8.));
|
|
|
|
// fresnel highlight
|
|
surf += clamp((t-.06)*8., 0.,1.6) *
|
|
(.2+.8*ao) * vec3(.7,.8,1.) * fres;
|
|
|
|
// environment map
|
|
surf += .2 * (1.-fres) * ao * skyColor(rrd);
|
|
|
|
// distance fog
|
|
col = surf * pow(1.-t / max_t, 1.3);
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
|
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
|
{
|
|
vec2 suv = fragCoord.xy / iResolution.xy;
|
|
vec2 uv = (fragCoord.xy - iResolution.xy*.5) / iResolution.y * 2.;
|
|
|
|
float ti = (iGlobalTime-14.)/8.;
|
|
|
|
vec3 ro = path(ti);
|
|
vec3 look = path(ti+.5);
|
|
float turn = (ro.x-look.x)*1.;
|
|
|
|
// lazily copied from Shane
|
|
// (except the hacky turn param)
|
|
float FOV = .7; // FOV - Field of view.
|
|
vec3 fwd = normalize(look-ro);
|
|
vec3 rgt = normalize(vec3(fwd.z, turn, -fwd.x));
|
|
vec3 up = cross(fwd, rgt);
|
|
|
|
vec3 rd = normalize(fwd + FOV*(uv.x*rgt + uv.y*up));
|
|
|
|
|
|
vec3 col = rayColor(ro, rd);
|
|
//col = skyColor(rd);
|
|
|
|
col *= pow(1.-dot(suv-.5,suv-.5)/.5, .6);
|
|
|
|
fragColor = vec4(pow(col,vec3(.8)),1.0);
|
|
}
|
|
|
|
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);
|
|
}
|