364 lines
9.0 KiB
GLSL
364 lines
9.0 KiB
GLSL
#version 330
|
|
|
|
precision mediump float;
|
|
|
|
float EPS = 0.0001;
|
|
float PI = 3.14159265359;
|
|
float FLT_MAX = 900.;
|
|
|
|
uniform float u_time;
|
|
uniform vec2 u_resolution;
|
|
|
|
layout(location = 1) out vec4 my_fragColor;
|
|
|
|
const int maxIterations = 64;
|
|
const float stepScale = 1.;
|
|
const float stopThreshold = .005;
|
|
|
|
float fov = .6;
|
|
float nearClip = 0.;
|
|
float farClip = 80.;
|
|
|
|
struct Light {
|
|
vec3 position;
|
|
float intensity;
|
|
vec3 color;
|
|
};
|
|
|
|
struct Surface {
|
|
float dist;
|
|
vec3 position;
|
|
vec3 baseColor;
|
|
vec3 normal;
|
|
vec3 emissiveColor;
|
|
};
|
|
|
|
struct Hit {
|
|
Surface surface;
|
|
Surface near;
|
|
};
|
|
|
|
float saturate(float s) {
|
|
return clamp(s, 0., 1.);
|
|
}
|
|
|
|
float distanceToLine(vec3 origin, vec3 dir, vec3 point) {
|
|
vec3 pointToOrigin = point - origin;
|
|
float pointToOriginLength = length(pointToOrigin);
|
|
vec3 pointToOriginNorm = normalize(pointToOrigin);
|
|
float theta = dot(dir, pointToOriginNorm);
|
|
return pointToOriginLength * sqrt(1. - theta * theta);
|
|
}
|
|
|
|
mat4 scale(vec3 s) {
|
|
mat4 m = mat4(
|
|
s.x, 0., 0., 0.,
|
|
0., s.y, 0., 0.,
|
|
0., 0., s.z, 0.,
|
|
0., 0., 0., 1.
|
|
);
|
|
return inverse(m);
|
|
}
|
|
|
|
mat4 rotateX(float angle) {
|
|
return inverse(mat4(
|
|
1., 0., 0., 0.,
|
|
0., cos(angle), -sin(angle), 0.,
|
|
0., sin(angle), cos(angle), 0.,
|
|
0., 0., 0., 1.
|
|
));
|
|
}
|
|
|
|
mat4 rotateY(float angle) {
|
|
return inverse(mat4(
|
|
cos(angle), 0., sin(angle), 0.,
|
|
0., 1., 0., 0.,
|
|
-sin(angle), 0., cos(angle), 0.,
|
|
0., 0., 0., 1.
|
|
));
|
|
}
|
|
|
|
mat4 rotateZ(float angle) {
|
|
return inverse(mat4(
|
|
cos(angle), -sin(angle), 0., 0.,
|
|
sin(angle), cos(angle), 0., 0.,
|
|
0., 0., 1., 0.,
|
|
0., 0., 0., 1.
|
|
));
|
|
}
|
|
|
|
mat4 translate(vec3 p) {
|
|
return inverse(mat4(
|
|
1., 0., 0., p.x,
|
|
0., 1., 0., p.y,
|
|
0., 0., 1., p.z,
|
|
0., 0., 0., 1.
|
|
));
|
|
}
|
|
|
|
float sphere(vec3 p, float size) {
|
|
return length(p) - size;
|
|
}
|
|
|
|
float box(vec3 p, vec3 size) {
|
|
vec3 d = abs(p) - size;
|
|
return length(max(d, 0.)) + min(max(d.x, max(d.y, d.z)), 0.);
|
|
}
|
|
|
|
float tube2(vec2 p, float size) {
|
|
return length(p) - size;
|
|
}
|
|
|
|
float box2(vec2 p, float size) {
|
|
return length(max(abs(p) - size, 0.));
|
|
}
|
|
|
|
float cylindar(vec3 p, vec3 c) {
|
|
return length(p.xz - c.xy) - c.z;
|
|
}
|
|
|
|
float displacement(vec3 p, vec3 power) {
|
|
return sin(power.x * p.x) * sin(power.y * p.y) * sin(power.z * p.z);
|
|
}
|
|
|
|
vec3 repeat(vec3 p, float c) {
|
|
return mod(p, c) - c * .5;
|
|
}
|
|
|
|
float smin(float a, float b, float k) {
|
|
float res = exp(-k * a) + exp(-k * b);
|
|
return -log(res) / k;
|
|
}
|
|
|
|
float scene(vec3 p) {
|
|
vec3 _p = p;
|
|
|
|
_p = (vec4(_p, 1.)).xyz;
|
|
|
|
return min(
|
|
sphere((vec4(p, 1.) * translate(vec3(-.7, 0., 0.))).xyz, .5),
|
|
box((vec4(p, 1.) * translate(vec3(.7, 0., 0))).xyz, vec3(.45))
|
|
);
|
|
}
|
|
|
|
float calcAO(vec3 p, vec3 n) {
|
|
float k = 1.;
|
|
float occ = 0.;
|
|
for(int i = 0; i < 5; i++) {
|
|
float len = .15 * (float(i) + 1.);
|
|
float distance = scene(n * len + p);
|
|
occ += (len - distance) * k;
|
|
k *= .5;
|
|
}
|
|
return clamp(1. - occ, 0., 1.);
|
|
}
|
|
|
|
vec3 getNormal(vec3 p) {
|
|
const float e = EPS;
|
|
return normalize(vec3(
|
|
scene(p + vec3(e, 0.0, 0.0)) - scene(p + vec3(-e, 0.0, 0.0)),
|
|
scene(p + vec3(0.0, e, 0.0)) - scene(p + vec3(0.0, -e, 0.0)),
|
|
scene(p + vec3(0.0, 0.0, e)) - scene(p + vec3(0.0, 0.0, -e))
|
|
));
|
|
}
|
|
|
|
Surface near(Surface needle, Surface target) {
|
|
if(needle.dist < 0. || needle.dist < target.dist) {
|
|
return needle;
|
|
}
|
|
return target;
|
|
}
|
|
|
|
Hit rayMarching(vec3 origin, vec3 dir, float start, float end) {
|
|
Surface cs; // current surface
|
|
cs.dist = -1.;
|
|
|
|
Surface ns; // near surface
|
|
ns.dist = FLT_MAX;
|
|
|
|
Hit hit;
|
|
|
|
float sceneDist = 0.;
|
|
float rayDepth = start;
|
|
|
|
for(int i = 0; i < maxIterations; i++) {
|
|
sceneDist = scene(origin + dir * rayDepth);
|
|
|
|
// cache near distance
|
|
if(sceneDist < ns.dist) {
|
|
ns.dist = sceneDist;
|
|
}
|
|
|
|
if((sceneDist < stopThreshold) || (rayDepth >= end)) {
|
|
break;
|
|
}
|
|
rayDepth += sceneDist * stepScale;
|
|
cs.dist = rayDepth;
|
|
}
|
|
|
|
if (sceneDist >= stopThreshold) {
|
|
rayDepth = end;
|
|
}
|
|
|
|
cs.dist = rayDepth;
|
|
hit.surface = cs;
|
|
hit.near = ns;
|
|
|
|
return hit;
|
|
}
|
|
|
|
float getSpecular(vec3 position, vec3 normal, Light light, float diffuse, vec3 cameraPos) {
|
|
vec3 lightDir = light.position - position;
|
|
vec3 ref = reflect(-normalize(lightDir), normal);
|
|
float specular = 0.;
|
|
if(diffuse > 0.) {
|
|
specular = max(0., dot(ref, normalize(cameraPos - normal)));
|
|
float specularPower = 32.;
|
|
specular = pow(specular, specularPower) * light.intensity;
|
|
}
|
|
return specular;
|
|
}
|
|
|
|
vec3 lighting(Surface surface, vec3 cameraPos) {
|
|
vec3 position = surface.position;
|
|
|
|
vec3 color = vec3(0.);
|
|
vec3 sceneColor = vec3(0.);
|
|
vec3 normal = getNormal(position);
|
|
|
|
vec3 objColor = vec3(.4, .4, .4);
|
|
vec3 specularColor = vec3(.6, .6, .6);
|
|
|
|
Light directionalLight;
|
|
directionalLight.position = vec3(5., 5., 5.);
|
|
directionalLight.intensity = .8;
|
|
directionalLight.color = vec3(.4, .4, .4);
|
|
|
|
Light pointLight;
|
|
pointLight.position = vec3(5., 5., 5.);
|
|
pointLight.intensity = .8;
|
|
pointLight.color = vec3(.5, .5, .5);
|
|
|
|
Light ambientLight;
|
|
ambientLight.color = vec3(.1, .1, .1);
|
|
ambientLight.intensity = .3;
|
|
|
|
// directional light
|
|
float dDiffuse = max(0., dot(normal, normalize(directionalLight.position)));
|
|
dDiffuse *= directionalLight.intensity;
|
|
vec3 dDiffuseColor = dDiffuse * directionalLight.color * objColor;
|
|
float dSpecular = getSpecular(position, normal, directionalLight, dDiffuse, cameraPos);
|
|
vec3 dSpecularColor = dSpecular * specularColor;
|
|
|
|
// point light
|
|
vec3 pLightDir = pointLight.position - position;
|
|
float pDiffuse = max(0., dot(normal, normalize(pLightDir)));
|
|
vec3 pDiffuseColor = pDiffuse * pointLight.color * objColor;
|
|
float d = distance(pointLight.position, position);
|
|
vec3 k = vec3(.05, .9, .06);
|
|
float attenuation = 1. / (k.x + (k.y * d) + (k.z * d * d));
|
|
pDiffuse *= pointLight.intensity;
|
|
pDiffuse *= attenuation;
|
|
float pSpecular = getSpecular(position, normal, pointLight, pDiffuse, cameraPos);
|
|
pSpecular *= attenuation;
|
|
vec3 pSpecularColor = pSpecular * specularColor;
|
|
|
|
// ambient
|
|
vec3 ambientColor = ambientLight.color * ambientLight.intensity * objColor;
|
|
float ao = calcAO(position, normal);
|
|
|
|
vec3 diffuse = dDiffuseColor + pDiffuseColor;
|
|
vec3 specular = dSpecularColor + pSpecularColor;
|
|
vec3 ambient = ambientColor * ao;
|
|
|
|
// color += objColor * diffuse + specular + ambient * ao;
|
|
color += objColor * diffuse + ambient * ao;
|
|
|
|
return color;
|
|
}
|
|
|
|
vec3 emissiveLight(Light light, Surface surface, vec3 rayOrigin, vec3 rayDirection) {
|
|
vec3 eyeDirection = rayOrigin + rayDirection;
|
|
|
|
float lightEmissive = pow(distanceToLine(eyeDirection, rayDirection, light.position) + .95, -2.);
|
|
|
|
float c = dot(surface.normal, normalize(light.position - surface.position));
|
|
c = clamp(c, 0., 1.);
|
|
float em = 0.;
|
|
|
|
em = c + (1. - c) * step(farClip, surface.dist);
|
|
|
|
return lightEmissive * light.color * light.intensity * em;
|
|
}
|
|
|
|
vec3 emissiveLighting(Surface surface, vec3 rayOrigin, vec3 rayDirection) {
|
|
vec3 eyeDirection = rayOrigin + rayDirection;
|
|
vec3 normal = surface.normal;
|
|
|
|
Light pointLightRed;
|
|
pointLightRed.color = vec3(1., .1, .1);
|
|
pointLightRed.intensity = 1.;
|
|
pointLightRed.position = vec3(cos(u_time * 1.4) * 2., sin(u_time * 1.4) * 2., 0.);
|
|
|
|
Light pointLightGreen;
|
|
pointLightGreen.color = vec3(.1, 1., .1);
|
|
pointLightGreen.intensity = 1.;
|
|
pointLightGreen.position = vec3(cos(u_time * 1.6) * 2., 0., sin(u_time * 1.6) * 2.);
|
|
|
|
Light pointLightBlue;
|
|
pointLightBlue.color = vec3(.1, .1, 1.);
|
|
pointLightBlue.intensity = 1.;
|
|
pointLightBlue.position = vec3(0., sin(u_time * 1.8) * 2., cos(u_time * 1.8) * 2.);
|
|
|
|
|
|
vec3 color = vec3(0.);
|
|
color += emissiveLight(pointLightRed, surface, rayOrigin, rayDirection);
|
|
color += emissiveLight(pointLightGreen, surface, rayOrigin, rayDirection);
|
|
color += emissiveLight(pointLightBlue, surface, rayOrigin, rayDirection);
|
|
|
|
return color;
|
|
}
|
|
|
|
|
|
void main() {
|
|
/*vec2 aspect = vec2(u_resolution.x / u_resolution.y, 1.);
|
|
vec2 screenCoord = (2. * gl_FragCoord.xy / u_resolution.xy - 1.) * aspect;
|
|
// vec2 mouse = u_mouse.xy / u_resolution.xy - .5;
|
|
|
|
// camera settings
|
|
vec3 lookAt = vec3(0., 0., 0.);
|
|
vec3 cameraPos = vec3(0.,0., 5.);
|
|
|
|
// camera vectors
|
|
vec3 forward = normalize(lookAt - cameraPos);
|
|
vec3 right = normalize(cross(forward, vec3(0., 1., 0.)));
|
|
vec3 up = normalize(cross(right, forward));
|
|
|
|
// raymarch
|
|
vec3 rayOrigin = cameraPos;
|
|
vec3 rayDirection = normalize(forward + fov * screenCoord.x * right + fov * screenCoord.y * up);
|
|
Hit hit = rayMarching(rayOrigin, rayDirection, nearClip, farClip);
|
|
Surface surface = hit.surface;
|
|
Surface near = hit.near;
|
|
|
|
surface.position = rayOrigin + rayDirection * surface.dist;
|
|
|
|
// color
|
|
vec3 sceneColor = vec3(0.);
|
|
|
|
// no hit or too far
|
|
if(surface.dist >= farClip) {
|
|
vec3 bgColor = vec3(0.);
|
|
sceneColor = bgColor;
|
|
} else {
|
|
sceneColor += lighting(surface, cameraPos);
|
|
}
|
|
|
|
surface.normal = getNormal(surface.position);
|
|
sceneColor += emissiveLighting(surface, rayOrigin, rayDirection);
|
|
*/
|
|
|
|
// my_fragColor = vec4(sceneColor, 1.);
|
|
my_fragColor = vec4(vec3(0., 1., 0.), 1.);
|
|
}
|