Files
4kintro/shader_test.glsl
2024-06-02 21:24:14 +03:00

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.);
}