2023-11-09 20:09:35 -05:00
|
|
|
#version 430
|
2023-11-11 21:59:53 -05:00
|
|
|
#extension GL_NV_uniform_buffer_std430_layout : enable
|
2023-11-06 22:02:45 -05:00
|
|
|
|
|
|
|
uniform mat4 P;
|
|
|
|
uniform mat4 V;
|
|
|
|
uniform mat4 M;
|
|
|
|
uniform vec3 cam_pos;
|
|
|
|
uniform int window_width;
|
|
|
|
uniform int window_height;
|
|
|
|
|
2023-11-07 00:15:16 -05:00
|
|
|
uniform float smoothing;
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
const uint P_SPHERE = 0x00;
|
|
|
|
const uint P_TORUS = 0x01;
|
|
|
|
const uint P_CONE = 0x02;
|
|
|
|
const uint P_CUBE = 0x03;
|
2023-11-13 00:10:20 -05:00
|
|
|
const uint P_ROUNDED_CUBE = 0x04;
|
2023-11-12 23:05:22 -05:00
|
|
|
|
2023-12-07 17:10:20 -05:00
|
|
|
//bool twoExists = false;
|
2023-11-16 17:06:00 -05:00
|
|
|
|
2023-11-11 21:59:53 -05:00
|
|
|
struct GLSLPrimitive
|
2023-11-09 20:09:35 -05:00
|
|
|
{
|
2023-11-11 21:59:53 -05:00
|
|
|
vec4 position;
|
|
|
|
vec4 diffuse_color;
|
|
|
|
vec4 specular_color;
|
|
|
|
vec4 ambient_color;
|
|
|
|
|
2023-11-13 00:10:20 -05:00
|
|
|
int specular_exponent;
|
2023-11-09 20:09:35 -05:00
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
uint type;
|
2023-11-09 20:09:35 -05:00
|
|
|
|
|
|
|
float radius;
|
|
|
|
float height;
|
|
|
|
float inner_radius;
|
|
|
|
float outer_radius;
|
2023-11-11 21:59:53 -05:00
|
|
|
float size;
|
2023-11-12 23:05:22 -05:00
|
|
|
uint dummy;
|
2023-11-16 17:06:00 -05:00
|
|
|
uint subtract;
|
|
|
|
uint dummy2;
|
|
|
|
uint dummy3;
|
|
|
|
uint dummy4;
|
2023-11-11 21:59:53 -05:00
|
|
|
};
|
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
struct GLSLLight
|
|
|
|
{
|
|
|
|
vec4 position;
|
|
|
|
vec4 diffuse_color;
|
|
|
|
vec4 specular_color;
|
|
|
|
vec4 ambient_color;
|
|
|
|
};
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
layout(std430, binding = 0) buffer PrimitiveBuffer
|
|
|
|
{
|
2023-11-11 21:59:53 -05:00
|
|
|
GLSLPrimitive primitives[];
|
|
|
|
};
|
2023-11-09 20:09:35 -05:00
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
layout(std430, binding = 1) buffer LightBuffer
|
|
|
|
{
|
|
|
|
GLSLLight lights[];
|
|
|
|
};
|
|
|
|
|
2023-11-06 22:02:45 -05:00
|
|
|
out vec4 FragColor;
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
struct NormalEstimationData
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
vec3 normal;
|
|
|
|
float minDistance;
|
|
|
|
float secondMinDistance;
|
|
|
|
float smoothMinDistance;
|
|
|
|
GLSLPrimitive closestPrimitive;
|
|
|
|
GLSLPrimitive secondClosestPrimitive;
|
2023-11-06 22:02:45 -05:00
|
|
|
};
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float sphereSDF(vec3 p, vec3 center, float r)
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
|
|
|
return length(p - center) - r;
|
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float torusSDF(vec3 p, vec3 center, float R, float r)
|
|
|
|
{
|
2023-11-11 21:59:53 -05:00
|
|
|
vec2 q = vec2(length(p.xz - center.xz) - R, p.y - center.y);
|
2023-11-06 22:02:45 -05:00
|
|
|
return length(q) - r;
|
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float coneSDF(vec3 p, vec3 center, float h, float r)
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
|
|
|
|
return length(d) < 0.0 ? max(d.x, -d.y) : length(max(d, vec2(0)));
|
2023-11-06 22:02:45 -05:00
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float cubeSDF(vec3 p, vec3 c, float s)
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
float x = max(p.x - c.x - (s / 2.0), c.x - p.x - (s / 2.0));
|
|
|
|
float y = max(p.y - c.y - (s / 2.0),c.y - p.y - (s / 2.0));
|
|
|
|
float z = max(p.z - c.z - (s / 2.0),c.z - p.z - (s / 2.0));
|
|
|
|
|
|
|
|
float d = x;
|
|
|
|
d = max(d, y);
|
|
|
|
d = max(d, z);
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2023-11-13 00:10:20 -05:00
|
|
|
float roundedCubeSDF(vec3 p, vec3 center, float s, float r) {
|
|
|
|
return length(max(abs(p - center) - vec3(s), vec3(0))) - r;
|
|
|
|
}
|
|
|
|
|
2023-12-07 17:10:20 -05:00
|
|
|
//float round(vec3 pos, GLSLPrimitive prim, float radius)
|
|
|
|
//{
|
|
|
|
// return sdf(pos, prim) - radius;
|
|
|
|
//}
|
|
|
|
|
|
|
|
float sdBox()
|
|
|
|
{
|
|
|
|
vec3 p = vec3(0.0, 0.0, 0.0);
|
|
|
|
vec3 b = vec3(0.0, 0.0, 0.1);
|
|
|
|
vec3 q = abs(p) - b;
|
|
|
|
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
|
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float sdf(vec3 pos, GLSLPrimitive prim)
|
|
|
|
{
|
|
|
|
float d;
|
|
|
|
switch (prim.type)
|
|
|
|
{
|
|
|
|
case P_SPHERE:
|
|
|
|
{
|
|
|
|
d = sphereSDF(pos, prim.position.xyz, prim.radius);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case P_TORUS:
|
|
|
|
{
|
|
|
|
d = torusSDF(pos, prim.position.xyz, prim.outer_radius, prim.inner_radius);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case P_CONE:
|
|
|
|
{
|
|
|
|
d = coneSDF(pos, prim.position.xyz, prim.height, prim.radius);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case P_CUBE:
|
|
|
|
{
|
|
|
|
d = cubeSDF(pos, prim.position.xyz, prim.size);
|
|
|
|
break;
|
|
|
|
}
|
2023-11-13 00:10:20 -05:00
|
|
|
case P_ROUNDED_CUBE:
|
|
|
|
{
|
|
|
|
d = roundedCubeSDF(pos, prim.position.xyz, prim.size, prim.radius);
|
2023-12-07 17:10:20 -05:00
|
|
|
//d = round(pos, prim, prim.radius);
|
|
|
|
//d = sdBox();
|
2023-11-13 00:10:20 -05:00
|
|
|
break;
|
|
|
|
}
|
2023-11-12 23:05:22 -05:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
d = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return d;
|
2023-11-06 22:02:45 -05:00
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float smoothMinSDF(float d1, float d2, float k)
|
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
if (k == 0.0) return min(d1, d2);
|
|
|
|
float h = max(k - abs(d1 - d2), 0.0) / k;
|
2023-11-06 22:02:45 -05:00
|
|
|
return min(d1, d2) - h * h * h * k * 1.0 / 6.0;
|
|
|
|
}
|
|
|
|
|
2023-11-12 23:05:22 -05:00
|
|
|
float smoothMaxSDF(float d1, float d2, float k)
|
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
if (k == 0.0) return max(d1, d2);
|
|
|
|
float h = max(k - abs(d1 - d2), 0.0) / k;
|
|
|
|
return max(d1, d2) - h * h * k * 0.25;
|
2023-11-06 22:02:45 -05:00
|
|
|
}
|
|
|
|
|
2023-12-07 17:10:20 -05:00
|
|
|
// From Inigo Quilez
|
|
|
|
float smoothSubSDF(float d1, float d2, float k)
|
2023-11-12 23:05:22 -05:00
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0);
|
|
|
|
return mix(d2, -d1, h) + k * h * (1.0 - h);
|
|
|
|
}
|
2023-11-12 23:05:22 -05:00
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
float calcDist(vec3 pos, inout float dist)
|
|
|
|
{
|
2023-11-16 17:06:00 -05:00
|
|
|
for (int i = 0; i < primitives.length(); i++)
|
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
float newDist = sdf(pos, primitives[i]);
|
2023-11-12 23:05:22 -05:00
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
if (primitives[i].subtract == 0)
|
|
|
|
dist = smoothMinSDF(dist, newDist, smoothing);
|
|
|
|
else
|
2023-12-07 17:10:20 -05:00
|
|
|
dist = smoothSubSDF(newDist, dist, smoothing);
|
2023-11-30 17:33:35 -05:00
|
|
|
}
|
2023-11-12 23:05:22 -05:00
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
return dist;
|
2023-11-16 17:06:00 -05:00
|
|
|
}
|
2023-11-12 23:05:22 -05:00
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
float calcDist2(vec3 pos)
|
2023-11-16 17:06:00 -05:00
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
float dist = 999999.0;
|
2023-11-16 17:06:00 -05:00
|
|
|
|
|
|
|
for (int i = 0; i < primitives.length(); i++)
|
2023-11-12 23:05:22 -05:00
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
float newDist = sdf(pos, primitives[i]);
|
|
|
|
|
|
|
|
if (primitives[i].subtract == 0)
|
|
|
|
dist = smoothMinSDF(newDist, dist, smoothing);
|
|
|
|
else
|
2023-12-07 17:10:20 -05:00
|
|
|
dist = smoothSubSDF(newDist, dist, smoothing);
|
2023-11-12 23:05:22 -05:00
|
|
|
}
|
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
return dist;
|
2023-11-12 23:05:22 -05:00
|
|
|
}
|
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
vec3 estimateNormals(vec3 p, float epsilon)
|
2023-11-12 23:05:22 -05:00
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
vec2 e = vec2(1.0, -1.0) * 0.5773;
|
|
|
|
return normalize(e.xyy * calcDist2(p + e.xyy * epsilon) +
|
|
|
|
e.yyx * calcDist2(p + e.yyx * epsilon) +
|
|
|
|
e.yxy * calcDist2(p + e.yxy * epsilon) +
|
|
|
|
e.xxx * calcDist2(p + e.xxx * epsilon));
|
|
|
|
}
|
2023-11-12 23:05:22 -05:00
|
|
|
|
|
|
|
vec4 blendColors(vec4 color1, vec4 color2, float blendFactor)
|
|
|
|
{
|
|
|
|
return mix(color1, color2, blendFactor);
|
2023-11-07 01:17:16 -05:00
|
|
|
}
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-13 00:10:20 -05:00
|
|
|
float weightFunction(float distance, float k, float epsilon)
|
|
|
|
{
|
|
|
|
if (k <= 0.0)
|
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
// When k is zero, return 1 if the distance is zero (object is closest), else return 0.
|
|
|
|
return distance <= 0.001 ? 1.0 : 0.0;
|
|
|
|
}
|
2023-11-13 00:10:20 -05:00
|
|
|
else
|
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
// As k increases, the transition becomes smoother.
|
|
|
|
return (k * k * k) / distance;
|
|
|
|
}
|
|
|
|
}
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-16 17:06:00 -05:00
|
|
|
vec4 renderLight(vec4 position) {
|
|
|
|
vec4 newPosition = position;
|
2023-12-07 17:10:20 -05:00
|
|
|
vec4 matPos = P * V * newPosition;
|
2023-11-16 17:06:00 -05:00
|
|
|
matPos /= matPos.w;
|
|
|
|
vec2 screenPos = 2.0 * vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height) - 1.0;
|
|
|
|
float aspectRatio = float(window_width) / float(window_height);
|
|
|
|
screenPos.y /= aspectRatio;
|
|
|
|
|
|
|
|
vec2 centerScreenPos = matPos.xy;
|
|
|
|
|
|
|
|
float radius = 0.05 / length(newPosition.xyz - cam_pos);
|
|
|
|
|
|
|
|
vec4 color;
|
|
|
|
if (length(screenPos - centerScreenPos) < radius && length(screenPos - centerScreenPos) > radius * 0.9) {
|
2023-12-07 17:10:20 -05:00
|
|
|
color = vec4(0.957, 0.827, 0.369, 1.0);
|
2023-11-16 17:06:00 -05:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
color = vec4(0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
2023-12-07 17:10:20 -05:00
|
|
|
vec4 RayMarch(vec2 coords, vec2 offset)
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
|
|
|
vec3 normals;
|
2023-11-16 17:06:00 -05:00
|
|
|
vec4 color = vec4(0.0);
|
|
|
|
vec4 lightColor = vec4(0.0);
|
2023-11-06 22:02:45 -05:00
|
|
|
vec4 ray_pos = vec4(cam_pos, 1.0);
|
|
|
|
float ray_dist = 0.0;
|
|
|
|
float max_dist = 100.0;
|
2023-11-13 11:29:48 -05:00
|
|
|
float epsilon = 0.001;
|
2023-11-06 22:02:45 -05:00
|
|
|
int steps = 0;
|
|
|
|
int max_steps = 1000;
|
2023-11-07 00:15:16 -05:00
|
|
|
float k = smoothing;
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-12-07 17:10:20 -05:00
|
|
|
vec4 cam_dir = inverse(P) * vec4(coords + offset, 1.0, 1.0);
|
2023-11-06 22:02:45 -05:00
|
|
|
cam_dir /= cam_dir.w;
|
|
|
|
cam_dir = vec4(cam_dir.xyz, 0.0);
|
|
|
|
|
|
|
|
vec4 ray_dir = normalize(inverse(V) * cam_dir);
|
|
|
|
|
2023-11-13 00:10:20 -05:00
|
|
|
vec4 accumulatedDiffuse = vec4(0.0);
|
|
|
|
vec4 accumulatedSpecular = vec4(0.0);
|
|
|
|
vec4 accumulatedAmbient = vec4(0.0);
|
|
|
|
float accumulatedSpecExp = 0.0;
|
2023-11-12 23:05:22 -05:00
|
|
|
float totalWeight = 0.0;
|
|
|
|
|
|
|
|
int closestIndex = -1;
|
|
|
|
|
2023-11-13 00:10:20 -05:00
|
|
|
while (ray_dist < max_dist && steps < max_steps && primitives.length() != 0)
|
2023-11-06 22:02:45 -05:00
|
|
|
{
|
|
|
|
steps++;
|
2023-11-12 23:05:22 -05:00
|
|
|
float minDist = 999999.0;
|
2023-12-07 17:10:20 -05:00
|
|
|
|
2023-11-30 17:33:35 -05:00
|
|
|
calcDist(ray_pos.xyz, minDist);
|
2023-11-12 23:05:22 -05:00
|
|
|
|
|
|
|
for (int i = 0; i < primitives.length(); i++)
|
|
|
|
{
|
2023-11-30 17:33:35 -05:00
|
|
|
float weight = weightFunction(minDist, smoothing, epsilon);
|
2023-11-13 00:10:20 -05:00
|
|
|
accumulatedDiffuse += primitives[i].diffuse_color * weight;
|
2023-12-07 17:10:20 -05:00
|
|
|
accumulatedSpecular += primitives[i].specular_color * weight;
|
2023-11-13 00:10:20 -05:00
|
|
|
accumulatedAmbient += primitives[i].ambient_color * weight;
|
|
|
|
accumulatedSpecExp += primitives[i].specular_exponent * weight;
|
2023-11-12 23:05:22 -05:00
|
|
|
totalWeight += weight;
|
|
|
|
}
|
|
|
|
|
2023-11-06 22:02:45 -05:00
|
|
|
if (minDist <= epsilon)
|
|
|
|
{
|
2023-11-12 23:05:22 -05:00
|
|
|
if (totalWeight > 0.0) {
|
2023-11-13 00:10:20 -05:00
|
|
|
accumulatedDiffuse /= totalWeight;
|
|
|
|
accumulatedSpecular /= totalWeight;
|
|
|
|
accumulatedAmbient /= totalWeight;
|
|
|
|
accumulatedSpecExp /= totalWeight;
|
2023-11-12 23:05:22 -05:00
|
|
|
}
|
|
|
|
|
2023-11-06 22:02:45 -05:00
|
|
|
vec4 ambient_color, diffuse_color;
|
2023-11-13 11:29:48 -05:00
|
|
|
vec4 ambient;
|
|
|
|
vec4 diffuse;
|
|
|
|
vec4 specular;
|
|
|
|
float distLight;
|
|
|
|
vec3 lw;
|
2023-11-13 00:10:20 -05:00
|
|
|
ambient_color = vec4(accumulatedAmbient.rgb, 1.0);
|
|
|
|
diffuse_color = vec4(accumulatedDiffuse.rgb, 1.0);
|
2023-11-30 17:33:35 -05:00
|
|
|
normals = estimateNormals(ray_pos.xyz, epsilon);
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
for (int i = 0; i < lights.length(); i++)
|
|
|
|
{
|
|
|
|
ambient += lights[i].ambient_color * ambient_color;
|
|
|
|
|
|
|
|
vec3 nw = normalize(normals);
|
|
|
|
lw = normalize(lights[i].position.xyz - ray_pos.xyz);
|
|
|
|
distLight = length(vec4(ray_pos.xyz - lights[i].position.xyz, 1.0));
|
|
|
|
diffuse += max(dot(nw, lw), 0) * diffuse_color * lights[i].diffuse_color;
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
float spec;
|
|
|
|
vec3 vw = normalize(cam_pos - ray_pos.xyz);
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
vec3 halfwayDir = normalize(lw + vw);
|
2023-12-07 17:10:20 -05:00
|
|
|
spec = pow(max(dot(halfwayDir, nw), 0), int(accumulatedSpecExp));
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-13 11:29:48 -05:00
|
|
|
specular += spec * accumulatedSpecular * lights[i].specular_color;
|
2023-11-06 22:02:45 -05:00
|
|
|
|
2023-11-16 17:06:00 -05:00
|
|
|
color = ambient + (1.0 / (distLight * distLight) * (diffuse + specular));
|
2023-11-13 11:29:48 -05:00
|
|
|
}
|
2023-11-06 22:02:45 -05:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ray_pos += ray_dir * minDist;
|
|
|
|
ray_dist += minDist;
|
|
|
|
}
|
|
|
|
|
2023-11-16 17:06:00 -05:00
|
|
|
for (int i = 0; i < lights.length(); i++) lightColor += renderLight(lights[i].position);
|
2023-12-07 17:10:20 -05:00
|
|
|
return vec4(mix(color, lightColor, lightColor.a).rgb, 0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void main(void)
|
|
|
|
{
|
|
|
|
vec4 finalColor = vec4(0.0);
|
|
|
|
int AA = 1; // Set the level of anti-aliasing
|
|
|
|
float invAA = 1.0 / float(AA*AA);
|
|
|
|
|
|
|
|
vec2 ndc_pos = 2.0 * vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height) - 1.0;
|
|
|
|
|
|
|
|
for (int y = 0; y < AA; ++y) {
|
|
|
|
for (int x = 0; x < AA; ++x) {
|
|
|
|
vec2 offset = vec2(float(x) / float(window_width), float(y) / float(window_height));
|
|
|
|
finalColor += RayMarch(ndc_pos, offset * invAA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
finalColor.rgb /= float(AA*AA);
|
|
|
|
finalColor.r = pow(finalColor.r, 1.0 / 2.2);
|
|
|
|
finalColor.g = pow(finalColor.g, 1.0 / 2.2);
|
|
|
|
finalColor.b = pow(finalColor.b, 1.0 / 2.2);
|
|
|
|
FragColor = finalColor;
|
2023-11-06 22:02:45 -05:00
|
|
|
}
|