#version 430 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; layout (std430, binding=2) buffer newPrim { vec3 diffuse_color; vec3 specular_color; vec3 ambient_color; vec3 position; int specular_exponent; int shape; float radius; float height; float inner_radius; float outer_radius; float size } out vec4 FragColor; struct Torus { float R; float r; }; Torus torus; struct Sphere { vec3 center; float r; }; Sphere sphere; void initTorus() { torus.R = 0.5; torus.r = 0.15; } void initSphere() { sphere.center = sphere_center; sphere.r = 0.25; } float sphereSDF(vec3 p, vec3 center, float r) { return length(p - center) - r; } float torusSDF(vec3 p, float R, float r) { vec2 q = vec2(length(p.xz) - R, p.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.R, torus.r) - torusSDF(vec3(p.x - epsilon, p.y, p.z), torus.R, torus.r); float y = torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.R, torus.r) - torusSDF(vec3(p.x, p.y - epsilon, p.z), torus.R, torus.r); float z = torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.R, torus.r) - torusSDF(vec3(p.x, p.y, p.z - epsilon), 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.R, torus.r), sphereSDF(p, sphere.center, sphere.r), smoothness); float nx = smoothMinSDF(torusSDF(vec3(p.x + epsilon, p.y, p.z), 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.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.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.R, torus.r), sphereSDF(p, sphere.center, sphere.r)); float nx = max(torusSDF(vec3(p.x + epsilon, p.y, p.z), 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.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.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; initTorus(); initSphere(); 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.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 = vec4(ka, 1.0); diffuse_color = vec4(kd, 1.0); 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(ks * 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); }