slang-shaders/procedural/sdf-platform.slang
2018-02-24 02:20:43 +01:00

444 lines
9 KiB
Plaintext

#version 450
// Xafer - 2017-04-30
// https://www.shadertoy.com/view/4dlyzl
// Reflections, refractions, lights such
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;
#define NEAR 0.01
#define FAR 12.0
#define STEP_SIZE 0.1
#define MAX_ITER 300
#define MAX_CYCLES 2
#define DELTA 0.01
#define A_SPEED 0.3
#define CAM_DIST 3.3
#define RECAST_MAX 5
#define GLOW_POWER 6.0
#define GLOW_COLOR vec3(0.2,0.4,0.4)
#define GRASS_SIZE vec2(0.005,0.4)
#define SKY_COLOR vec3(0.1,0.3,0.4)
//Structures
struct Light
{
vec3 pos;
vec3 color;
float radius;
float intensity;
};
struct lComp
{
vec3 specular;
float specularIntensity;
vec3 diffuse;
};
struct Ray
{
vec3 pos;
vec3 dir;
float dist;
float near;
};
struct Material
{
vec3 color;
float specular;
float diffuse;//
float ambient;//Ambient light factor
float refl;//How reflective is a surface
float refr;//Refraction index
float opacity;//For refractions
};
//Signed Distance Functions
float sdSphere(vec3 p)
{
return length(p) - 1.0;
}
float sdPlane(vec3 p)
{
return -p.y;
}
float sdBox( vec3 p)
{
vec3 d = abs(p) - vec3(1.0);
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
float opAdd(float d1, float d2)
{
return min(d1,d2);
}
float opSub(float d1, float d2)
{
return max(-d1,d2);
}
float opInter(float d1, float d2)
{
return max(d1,d2);
}
//Combinations
float walls(vec3 p)
{
p.y -= 1.0;
p.y * 2.0;
vec3 p2 = p;
vec3 p3 = p;
float width = 0.1;
vec2 dist = vec2(5.0);
p2.xz = mod(p2.xz,dist)-(dist/2.0);
p2.x /= width;
p2.z /= 2.0;
p3.xz = mod(p3.xz,dist)-(dist/2.0);
p3.z /= width;
p3.x /= 2.0;
float env = opAdd(sdPlane(p),opAdd(sdBox(p2),sdBox(p3)));
env = opSub(max(-p.y - 0.3, p.y + 0.2),max(env,sdSphere(p/(CAM_DIST-0.4))));
env = opAdd(env,sdSphere(p/0.7 + vec3(0,0.5,0)));
return opSub(sdSphere(p),env);
}
float map(vec3 pos, float factor)
{
return walls(pos);
}
float map(vec3 pos)
{
return map(pos,0.0);
}
//Environment propreties
vec3 getNormal(vec3 p)
{
vec2 delta = vec2 (DELTA, 0.0);
vec3 normal = normalize (vec3 (
map (p + delta.xyy) - map (p - delta.xyy),
map (p + delta.yxy) - map (p - delta.yxy),
map (p + delta.yyx) - map (p - delta.yyx)));
return normalize(normal);
}
Material getMaterial(vec3 pos)
{
Material mat;
mat.color = vec3(sin(pos.y),cos(pos.x),sin(pos.z))/2.0 + 0.5;
mat.refl = 0.0;
mat.refr = 0.8;
mat.opacity = 0.7;
mat.color = mix(mat.color,getNormal(pos),0.2);
return mat;
}
//RayMarching
Ray march(Ray ray, int iterations)
{
float n = 1.0 / min(iResolution.x, iResolution.y);
for(int i = 0; i < iterations; i++)
{
ray.near = map(ray.pos,sqrt(ray.dist)*n);
if(ray.near < DELTA || ray.dist > FAR)
break;
float n = ray.near * STEP_SIZE;
ray.pos += ray.dir * n;
ray.dist += n;
}
return ray;
}
lComp getLighting(Ray ray)
{
lComp lightComposition;
//Looping through lights
Light light;
light.radius = 3.5;
light.intensity = 1.0;
light.pos = vec3(0,-1,0);
light.color = vec3(1.0,0.8,0.6);
float specular;
float diffuse;
vec3 rayPos = ray.pos;
vec3 dir = light.pos - ray.pos;
float lDist = length(dir);
dir = normalize(dir);
rayPos += DELTA*dir;
float near = 0.0;
float dist = 0.0;
float l;
for(int i =0 ; i < MAX_ITER;i++)
{
near = map(rayPos);
l = length(rayPos-light.pos);
if(near < DELTA || dist > lDist)
break;
float n = abs(near * 0.1);
rayPos += n*dir;
dist += n;
}
if(near < DELTA)
diffuse = 0.0;
else if(dist > lDist)
{
diffuse = max(0.0,1.0 - (lDist/light.radius));
specular = dot(reflect(ray.dir,getNormal(ray.pos)),dir)/2.0 + 0.5;
specular = -cos(specular*3.1416)/2.0 + 0.5;
specular = pow(specular,lDist*lDist);
//if(specular > 0.9);
// specular /= 20.0;
}
vec3 normal = getNormal(ray.pos);
lightComposition.diffuse = mix(SKY_COLOR, light.color, diffuse);
lightComposition.specular = light.color;
lightComposition.specularIntensity = specular;
return lightComposition;
}
//Marching through refractions
vec3 getRefraction(Ray ray)
{
vec3 color;
float colorFactor;
float intensity = 1.0;
Material mat = getMaterial(ray.pos);;
for(int i = 0; i < MAX_CYCLES; i++)
{
vec3 normal = getNormal(ray.pos);
ray.dir = refract(ray.dir, normal, mat.refr);
vec3 m = ray.dir*DELTA*2.0;
int inside = 0;
for(int j = 0; j < MAX_ITER && (ray.near < DELTA || inside == 1); j++)
{
ray.pos += m;
ray.dist += DELTA*2.0;
ray.near = map(ray.pos);
}
ray.dir = refract(ray.dir,normal,mat.refr);
ray = march(ray,MAX_ITER);
if(ray.near > DELTA || ray.dist > FAR)
{
color += SKY_COLOR*intensity;
colorFactor += intensity;
break;
}
lComp lightComposition = getLighting(ray);
mat = getMaterial(ray.pos);
vec3 col = mix(mat.color * lightComposition.diffuse,lightComposition.specular, lightComposition.specularIntensity);
color += mix(col,SKY_COLOR,ray.dist/FAR)*intensity;
colorFactor += intensity;
intensity *= 1.0 - mat.opacity;
}
return color/colorFactor;
}
//Marching through reflections
vec3 getReflection(Ray ray)
{
vec3 color;
float colorFactor;
float intensity = 1.0;
for(int i = 0; i < MAX_CYCLES; i++)
{
vec3 normal = getNormal(ray.pos);
ray.dir = reflect(ray.dir,normal);
ray.pos += ray.dir * DELTA;
ray = march(ray, MAX_ITER);
Material mat = getMaterial(ray.pos);
intensity *= mat.refl;
lComp lightComposition = getLighting(ray);
vec3 col = mix(mat.color * lightComposition.diffuse, lightComposition.specular, lightComposition.specularIntensity);
color += mix(col,SKY_COLOR,ray.dist/FAR)*intensity;
colorFactor += intensity;
}
return color/colorFactor;
}
//Getting the color at the specified point
vec3 getColor(Ray ray)
{
vec3 color;
vec3 normal = getNormal(ray.pos);
if(ray.dist > FAR)
{
color = SKY_COLOR;
}
else if(ray.near <= DELTA)
{
Material mat = getMaterial(ray.pos);
color = mat.color;
lComp lightComposition = getLighting(ray);
color *= lightComposition.diffuse;
if(mat.refr > 0.0)
color = mix(getRefraction(ray),color,mat.opacity);
if(mat.refl > 0.0)
color = mix(color,getReflection(ray),mat.refl);
color = mix(color, lightComposition.specular, lightComposition.specularIntensity);
color = mix(color, SKY_COLOR , ray.dist/FAR);
color = mix(color, SKY_COLOR , dot(ray.dir,normal)/2.0 + 0.5);
}
return color;
}
vec3 castRay(vec3 origin, vec3 direction)
{
//Generating ray
Ray ray;
ray.pos = origin;
ray.dir = direction;
ray.dist = 0.0;
//Move the ray to a surface up to far distance
ray = march(ray, MAX_ITER*2);
return getColor(ray);
}
//Initialisation
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
//Setting up screen-correct uv
vec2 uv = ( fragCoord.xy / iResolution.xy ) * 2.0 - vec2( 1 );
uv.x *= iResolution.x/iResolution.y;
//Setting up rotation
float sa = sin( iGlobalTime * A_SPEED );
float ca = cos( iGlobalTime * A_SPEED );
float cDist = CAM_DIST + sin(iGlobalTime * A_SPEED);
//Creating ray
vec3 or = vec3(sa*cDist,0.5,-ca*cDist);
vec3 di = -normalize(vec3(uv.x,uv.y,-1.0));
//Rotating orientation
mat3 r;
r[0] = vec3(ca,0,sa);
r[1] = vec3(0,1,0);
r[2] = vec3(-sa,0,ca);
di = r*di;
vec3 color = castRay(or,di);
fragColor = vec4(color,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);
}