forked from mttu-developers/konabot
169 lines
4.4 KiB
GLSL
169 lines
4.4 KiB
GLSL
#version 330
|
|
const float EPS = 0.001;
|
|
const int MAX_ITER = 128;
|
|
const float INF = 1e10;
|
|
const float PI = 3.14159;
|
|
|
|
uniform vec2 u_resolution;
|
|
out vec4 fragColor;
|
|
|
|
struct sdQuery {
|
|
float value;
|
|
int obj_id;
|
|
};
|
|
|
|
float sdCube(vec3 p, vec3 b) {
|
|
p = abs(p) - b;
|
|
return length(max(p, 0.0)) + min(max(p.x, max(p.y, p.z)), 0.0);
|
|
}
|
|
|
|
float sdSphere(vec3 p, float r) {
|
|
return length(p) - r;
|
|
}
|
|
|
|
float sdCappedCylinder( vec3 p, float r, float h )
|
|
{
|
|
vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r,h);
|
|
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
|
|
}
|
|
|
|
float sdVerticalCapsule( vec3 p, float h, float r )
|
|
{
|
|
p.y -= clamp( p.y, 0.0, h );
|
|
return length( p ) - r;
|
|
}
|
|
float sdTorus( vec3 p, vec2 t )
|
|
{
|
|
vec2 q = vec2(length(p.xz)-t.x,p.y);
|
|
return length(q)-t.y;
|
|
}
|
|
// float smin( float a, float b, float k )
|
|
// {
|
|
// k *= 1.0;
|
|
// float r = exp2(-a/k) + exp2(-b/k);
|
|
// return -k*log2(r);
|
|
// }
|
|
|
|
float smin( float a, float b, float k )
|
|
{
|
|
k *= 2.0;
|
|
float x = (b-a)/k;
|
|
float g = 0.5*(x+sqrt(x*x+1.0));
|
|
return b - k * g;
|
|
}
|
|
|
|
sdQuery sd(vec3 p) {
|
|
sdQuery qry;
|
|
qry.value = INF;
|
|
qry.obj_id = -1;
|
|
<SDF_BLOCK>
|
|
return qry;
|
|
}
|
|
|
|
vec3 nrm(vec3 p) {
|
|
vec2 d = vec2(EPS, 0.0);
|
|
return normalize(vec3(
|
|
sd(p + d.xyy).value - sd(p - d.xyy).value,
|
|
sd(p + d.yxy).value - sd(p - d.yxy).value,
|
|
sd(p + d.yyx).value - sd(p - d.yyx).value
|
|
));
|
|
}
|
|
|
|
float saturate(float x) {
|
|
return clamp(x, 0.0, 1.0);
|
|
}
|
|
|
|
float ggx_distribution(vec3 n, vec3 h, float roughness) {
|
|
float alpha = roughness * roughness;
|
|
float alpha2 = alpha * alpha;
|
|
float NdotH = saturate(dot(n, h));
|
|
float denom = NdotH * NdotH * (alpha2 - 1.0) + 1.0;
|
|
return alpha2 / max(PI * denom * denom, EPS);
|
|
}
|
|
|
|
float geometry_schlick_ggx(float NdotX, float roughness) {
|
|
float r = roughness + 1.0;
|
|
float k = r * r / 8.0;
|
|
return NdotX / max(NdotX * (1.0 - k) + k, EPS);
|
|
}
|
|
|
|
float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) {
|
|
float NdotV = saturate(dot(n, v));
|
|
float NdotL = saturate(dot(n, l));
|
|
return geometry_schlick_ggx(NdotV, roughness) * geometry_schlick_ggx(NdotL, roughness);
|
|
}
|
|
|
|
vec3 fresnel_schlick(vec3 f0, float cos_theta) {
|
|
return f0 + (1.0 - f0) * pow(1.0 - saturate(cos_theta), 5.0);
|
|
}
|
|
|
|
vec3 tonemap_aces(vec3 c) {
|
|
const float a = 2.51;
|
|
const float b = 0.03;
|
|
const float c1 = 2.43;
|
|
const float d = 0.59;
|
|
const float e = 0.14;
|
|
return clamp((c * (a * c + b)) / (c * (c1 * c + d) + e), 0.0, 1.0);
|
|
}
|
|
|
|
vec4 materialColor(int obj_id) {
|
|
<COLOR_BLOCK>
|
|
return vec4(1.0);
|
|
}
|
|
|
|
vec4 color(vec3 p, vec3 r, int obj_id) {
|
|
vec3 light_col = vec3(1.0);
|
|
vec4 albedo = materialColor(obj_id);
|
|
vec3 N = nrm(p);
|
|
vec3 V = normalize(-r);
|
|
vec3 L = normalize(vec3(0.5, 0.8, -0.6));
|
|
vec3 H = normalize(V + L);
|
|
float roughness = 0.45;
|
|
float metallic = 0.02;
|
|
float NdotL = saturate(dot(N, L));
|
|
float NdotV = saturate(dot(N, V));
|
|
float D = ggx_distribution(N, H, roughness);
|
|
float G = geometry_smith(N, V, L, roughness);
|
|
vec3 F0 = mix(vec3(0.04), albedo.rgb, metallic);
|
|
vec3 F = fresnel_schlick(F0, dot(V, H));
|
|
vec3 kD = (1.0 - F) * (1.0 - metallic);
|
|
vec3 diffuse = kD * albedo.rgb / PI;
|
|
vec3 specular = D * G * F / max(4.0 * NdotL * NdotV, EPS);
|
|
|
|
float hemi = N.y * 0.5 + 0.5;
|
|
vec3 sky_ambient = vec3(0.60, 0.72, 0.92);
|
|
vec3 ground_ambient = vec3(0.18, 0.16, 0.14);
|
|
vec3 ambient = mix(ground_ambient, sky_ambient, hemi) * (diffuse + 0.25 * F0) * 0.35;
|
|
|
|
vec3 col = ambient + (diffuse + specular) * light_col * NdotL;
|
|
col = tonemap_aces(col);
|
|
col = pow(col, vec3(1.0 / 2.2));
|
|
return vec4(col, 1.0);
|
|
}
|
|
|
|
vec4 march(vec3 p, vec3 r) {
|
|
sdQuery qry;
|
|
vec4 col = vec4(0.0);
|
|
for(int i = 0; i < MAX_ITER; ++i) {
|
|
qry = sd(p);
|
|
if(qry.value < EPS){
|
|
col = color(p, r, qry.obj_id);
|
|
break;
|
|
}
|
|
p += qry.value * r;
|
|
}
|
|
return col;
|
|
}
|
|
|
|
void main() {
|
|
vec2 uv = 2. * (gl_FragCoord.xy / u_resolution - .5) * vec2(u_resolution.x / u_resolution.y, 1.);
|
|
vec3 c_p = vec3(<CAM_POS>);
|
|
vec3 c_z = normalize(vec3(<CAM_DIR>));
|
|
vec3 world_up = abs(c_z.y) > 0.999 ? vec3(0., 0., 1.) : vec3(0., 1., 0.);
|
|
vec3 c_x = normalize(cross(c_z, world_up));
|
|
vec3 c_y = normalize(cross(c_x, c_z));
|
|
mat3 view = mat3(c_x, c_y, c_z);
|
|
vec3 r = normalize(vec3(uv, <CAM_FOCUS>));
|
|
fragColor = march(c_p, view * r);
|
|
}
|