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