196 lines
5.8 KiB
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);
|
|
} |