parade/shaders/parade_fs.glsl

196 lines
5.8 KiB
GLSL

#version 430
#extension GL_NV_uniform_buffer_std430_layout : enable
uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
uniform vec3 cam_pos;
uniform int window_width;
uniform int window_height;
uniform vec3 la;
uniform vec3 ld;
uniform vec3 ls;
uniform vec3 ka;
uniform vec3 kd;
uniform vec3 ks;
uniform float smoothing;
uniform vec3 sphere_center;
struct GLSLPrimitive
{
vec4 position;
vec4 diffuse_color;
vec4 specular_color;
vec4 ambient_color;
unsigned int specular_exponent;
unsigned int type;
float radius;
float height;
float inner_radius;
float outer_radius;
float size;
};
layout(std430, binding = 0) buffer PrimitiveBuffer {
GLSLPrimitive primitives[];
};
out vec4 FragColor;
struct Torus
{
vec4 center;
float R;
float r;
};
Torus torus;
struct Sphere
{
vec3 center;
float r;
};
Sphere sphere;
void initTorus()
{
torus.center = primitives[1].position;
torus.R = primitives[1].inner_radius;
torus.r = primitives[1].height;
}
void initSphere()
{
sphere.center = primitives[0].position.xyz;
sphere.r = primitives[0].radius;
}
float sphereSDF(vec3 p, vec3 center, float r) {
return length(p - center) - r;
}
float torusSDF(vec3 p, vec4 center, float R, float r) {
vec2 q = vec2(length(p.xz - center.xz) - R, p.y - center.y);
return length(q) - r;
}
vec3 estimateNormalsSphere(vec3 p)
{
float epsilon = 0.001;
float x = sphereSDF(vec3(p.x + epsilon, p.y, p.z), sphere.center, sphere.r) - sphereSDF(vec3(p.x - epsilon, p.y, p.z), sphere.center, sphere.r);
float y = sphereSDF(vec3(p.x, p.y + epsilon, p.z), sphere.center, sphere.r) - sphereSDF(vec3(p.x, p.y - epsilon, p.z), sphere.center, sphere.r);
float z = sphereSDF(vec3(p.x, p.y, p.z + epsilon), sphere.center, sphere.r) - sphereSDF(vec3(p.x, p.y, p.z - epsilon), sphere.center, sphere.r);
return normalize(vec3(x, y, z));
}
vec3 estimateNormalsTorus(vec3 p)
{
float epsilon = 0.001;
float x = torusSDF(vec3(p.x + epsilon, p.y, p.z), torus.center, torus.R, torus.r) - torusSDF(vec3(p.x - epsilon, p.y, p.z), torus.center, torus.R, torus.r);
float y = torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.center, torus.R, torus.r) - torusSDF(vec3(p.x, p.y - epsilon, p.z), torus.center, torus.R, torus.r);
float z = torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.center, torus.R, torus.r) - torusSDF(vec3(p.x, p.y, p.z - epsilon), torus.center, torus.R, torus.r);
return normalize(vec3(x, y, z));
}
float smoothMinSDF(float d1, float d2, float k) {
if (k == 0.0) k = 0.000001;
float h = max(k - abs(d1 - d2), 0) / k;
return min(d1, d2) - h * h * h * k * 1.0 / 6.0;
}
float smoothMaxSDF(float d1, float d2, float k) {
if (k == 0.0) k = 0.000001;
float h = min(k - abs(d1 - d2), 0) / k;
return min(d1, d2) - h * h * h * k * 1.0 / 6.0;
}
vec3 estimateSmoothNormals(vec3 p, float smoothness) {
float epsilon = 0.001;
float d = smoothMinSDF(torusSDF(p, torus.center, torus.R, torus.r), sphereSDF(p, sphere.center, sphere.r), smoothness);
float nx = smoothMinSDF(torusSDF(vec3(p.x + epsilon, p.y, p.z), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x + epsilon, p.y, p.z), sphere.center, sphere.r), smoothness) - d;
float ny = smoothMinSDF(torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x, p.y + epsilon, p.z), sphere.center, sphere.r), smoothness) - d;
float nz = smoothMinSDF(torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x, p.y, p.z + epsilon), sphere.center, sphere.r), smoothness) - d;
return normalize(vec3(nx, ny, nz));
}
vec3 estimateNormalsMax(vec3 p, float smoothness) {
float epsilon = 0.001;
float d = max(torusSDF(p, torus.center, torus.R, torus.r), sphereSDF(p, sphere.center, sphere.r));
float nx = max(torusSDF(vec3(p.x + epsilon, p.y, p.z), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x + epsilon, p.y, p.z), sphere.center, sphere.r)) - d;
float ny = max(torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x, p.y + epsilon, p.z), sphere.center, sphere.r)) - d;
float nz = max(torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.center, torus.R, torus.r), sphereSDF(vec3(p.x, p.y, p.z + epsilon), sphere.center, sphere.r)) - d;
return normalize(vec3(nx, ny, nz));
}
void main(void)
{
vec3 normals;
vec3 color = la;
vec4 ray_pos = vec4(cam_pos, 1.0);
float ray_dist = 0.0;
float max_dist = 100.0;
float epsilon = 0.0001;
int steps = 0;
int max_steps = 1000;
vec3 light_pos = vec3(0.0, 1.0, 0.0);
int spec_exponent = 40;
float k = smoothing;
initSphere();
initTorus();
vec2 ndc_pos = 2.0 * vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height) - 1.0;
vec4 cam_dir = inverse(P) * vec4(ndc_pos, 1.0, 1.0);
cam_dir /= cam_dir.w;
cam_dir = vec4(cam_dir.xyz, 0.0);
vec4 ray_dir = normalize(inverse(V) * cam_dir);
while (ray_dist < max_dist && steps < max_steps)
{
steps++;
float distTorus = torusSDF(ray_pos.xyz, torus.center, torus.R, torus.r);
float distSphere = sphereSDF(ray_pos.xyz, sphere.center, sphere.r);
float minDist = smoothMinSDF(distTorus, distSphere, k);
if (minDist <= epsilon)
{
vec4 ambient_color, diffuse_color;
ambient_color = primitives[0].ambient_color;
diffuse_color = primitives[0].diffuse_color;
vec4 ambient = vec4(la, 1.0) * ambient_color;
normals = estimateSmoothNormals(ray_pos.xyz, k);
vec3 nw = normalize(normals);
vec3 lw = normalize(light_pos - ray_pos.xyz);
float dist = length(vec4(ray_pos.xyz - light_pos, 1.0));
vec4 diffuse = max(dot(nw, lw), 0) * diffuse_color * vec4(ld, 1.0);
float spec;
vec3 vw = normalize(cam_pos - ray_pos.xyz);
vec3 halfwayDir = normalize(lw + vw);
spec = pow(max(dot(halfwayDir, nw), 0), spec_exponent);
vec4 specular = spec * vec4(primitives[0].specular_color.rgb * ls, 1.0);
color = (ambient + (1.0 / (dist * dist) * (diffuse + specular))).xyz;
break;
}
ray_pos += ray_dir * minDist;
ray_dist += minDist;
}
FragColor = vec4(color, 1.0);
}