armory/Shaders/std/sdf.glsl
2017-08-02 11:46:54 +02:00

208 lines
5.7 KiB
GLSL

const float res = 50.0; // sdftex res
uniform sampler3D sdftex;
float mapsdf(vec3 p) {
p = clamp(p, vec3(-1.0), vec3(1.0));
p = p * 0.5 + 0.5;
return texture(sdftex, p).a;
}
vec4 mapsdf2(vec3 p) {
p = clamp(p, vec3(-1.0), vec3(1.0));
p = p * 0.5 + 0.5;
return texture(sdftex, p);
}
vec3 calcNormal(const vec3 pos, const float eps) {
const vec3 v1 = vec3( 1.0,-1.0,-1.0);
const vec3 v2 = vec3(-1.0,-1.0, 1.0);
const vec3 v3 = vec3(-1.0, 1.0,-1.0);
const vec3 v4 = vec3( 1.0, 1.0, 1.0);
return normalize(v1 * mapsdf(pos + v1 * eps) +
v2 * mapsdf(pos + v2 * eps) +
v3 * mapsdf(pos + v3 * eps) +
v4 * mapsdf(pos + v4 * eps));
}
float sdBox(vec3 p, vec3 b) {
vec3 d = abs(p) - b;
return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
}
float dfao(const vec3 p, const vec3 n) {
const float eps = 0.02;
float occ = 0.0;
float sca = 1.0;
for (int i = 0; i < 10; i++) {
float r = 0.01 + 0.1 * float(i);
vec3 rd = n * r;
vec3 sp = rd + p;
float d;
if (sdBox(sp, vec3(1.0)) <= 0.0) {
d = mapsdf(sp + rd);
// if (d < eps) break;
}
else {
vec3 sampleBorder = clamp(sp, vec3(-1.0), vec3(1.0));
float phi = mapsdf(sampleBorder);
float dd = 0.1;
float grad_x = mapsdf(sampleBorder + vec3(dd, 0, 0)) - phi;
float grad_y = mapsdf(sampleBorder + vec3(0, dd, 0)) - phi;
vec3 grad = vec3(grad_x, grad_y, 1.0);
vec3 endpoint = sampleBorder - normalize(grad) * phi;
d = distance(endpoint, sp);
}
occ += (r - d) * sca;
sca *= 0.85;
}
return clamp(1.0 - occ / (2.14), 0.0, 1.0);
}
// float dfrs(const vec3 p, const vec3 l) {
float dfrs(const vec3 p, const vec3 l, const vec3 lp) {
float visibility = 1.0;
const float distmax = 10.0;
const float eps = 0.01;
float dist = 0.05;
// float test = mapsdf(p);
// if (test < 0.1) {
// fragColor = vec4(1.0, 0.0, 0.0, 1.0);
// return;
// }
// float lastd = distmax;
for (int i = 0; i < 50; i++) {
vec3 rd = l * dist;
float d = sdBox(p + rd, vec3(1.0));
// Going out of volume box
// if (d > 0.0 && lastd < d) {
// visibility = 1.0;
// break;
// }
// lastd = d;
if (d <= 0.0) { // In volume
d = mapsdf(p + rd);
// if (distance(p + rd, lp) < 0.05) { // Hits light pos
if (dist + d > distance(p, lp) - 0.05) {
// visibility = 1.0;
break;
}
if (d < eps) {
visibility = 0.0;
break;
}
}
else { // To volume
// d += mapsdf(p + rd);
vec3 sampleBorder = clamp(p + rd, vec3(-1.0), vec3(1.0));
float phi = mapsdf(sampleBorder);
float dd = 0.1;
float grad_x = mapsdf(sampleBorder + vec3(dd, 0, 0)) - phi;
float grad_y = mapsdf(sampleBorder + vec3(0, dd, 0)) - phi;
vec3 grad = vec3(grad_x, grad_y, 1.0);
vec3 endpoint = sampleBorder - normalize(grad) * phi;
d = distance(endpoint, p + rd);
// float dd = 0.1;
// vec3 p0 = clamp(p, vec3(-1.0), vec3(1.0));
// vec3 p1 = clamp(p, vec3(-0.99), vec3(0.99));
// float r0 = mapsdf(p0);
// float r1 = mapsdf(p1);
// float h0 = 0.5 + (r0 * r0 - r1 * r1) / (2.0 * dd * dd);
// float ri = sqrt(abs(r0 * r0 - h0 * h0 * dd * dd));
// vec3 p2 = p0 + (p1 - p0) * h0;
// vec3 p3 = p2 + vec3(p1.z - p0.z, p1.y - p0.y, p1.x - p0.x) * ri;
// d = length((p + rd) - p3);
}
const float k = 4.0;
visibility = min(visibility, k * d / dist);
dist += d;
if (dist > distmax) {
break;
}
}
return visibility;
}
vec3 orthogonal(const vec3 u) {
// Pass normalized u
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector
return abs(dot(u, v)) > 0.99999 ? cross(u, vec3(0.0, 1.0, 0.0)) : cross(u, v);
}
vec3 traceCone(const vec3 p, const vec3 n) {
vec3 col = vec3(0.0);
const float eps = 0.02;
float dist = 0.05;
for (int i = 0; i < 10; i++) {
vec3 rd = n * dist;
float d = sdBox(p + rd, vec3(1.0));
if (d <= 0.0) {
vec4 res = mapsdf2(p + rd);
d = res.a;
if (d < eps) {
// float vis = dfrs(p + rd, l, lp);
// vec3 hitn = calcNormal(p + rd, 0.002);
// float diffuse = max(0.0, dot(hitn, l));// / dot(l,l);
col = res.rgb * max(1.0 - dist, 0.0);// * diffuse;// * vis;
break;
}
}
dist += d;
}
return col;
}
vec3 dfgi(const vec3 p, const vec3 n) {
const float ANGLE_MIX = 0.5; // Angle mix (1.0f -> orthogonal direction, 0.0f -> direction of normal)
const float w[3] = { 1.0, 1.0, 1.0 }; // Cone weights
// Find a base for the side cones with the normal as one of its base vectors
const vec3 ortho = normalize(orthogonal(n));
const vec3 ortho2 = normalize(cross(ortho, n));
// Find base vectors for the corner cones
const vec3 corner = 0.5 * (ortho + ortho2);
const vec3 corner2 = 0.5 * (ortho - ortho2);
// Find start position of trace (start with a bit of offset)
const vec3 offset = 0.0 * n;
const vec3 origin = p + offset;
vec3 col = vec3(0.0);
const float CONE_OFFSET = 0.0;//-0.01;
col += w[0] * traceCone(origin + CONE_OFFSET * n, n);
const vec3 s1 = mix(n, ortho, ANGLE_MIX);
const vec3 s2 = mix(n, -ortho, ANGLE_MIX);
const vec3 s3 = mix(n, ortho2, ANGLE_MIX);
const vec3 s4 = mix(n, -ortho2, ANGLE_MIX);
col += w[1] * traceCone(origin + CONE_OFFSET * ortho, s1);
col += w[1] * traceCone(origin - CONE_OFFSET * ortho, s2);
col += w[1] * traceCone(origin + CONE_OFFSET * ortho2, s3);
col += w[1] * traceCone(origin - CONE_OFFSET * ortho2, s4);
const vec3 c1 = mix(n, corner, ANGLE_MIX);
const vec3 c2 = mix(n, -corner, ANGLE_MIX);
const vec3 c3 = mix(n, corner2, ANGLE_MIX);
const vec3 c4 = mix(n, -corner2, ANGLE_MIX);
col += w[2] * traceCone(origin + CONE_OFFSET * corner, c1);
col += w[2] * traceCone(origin - CONE_OFFSET * corner, c2);
col += w[2] * traceCone(origin + CONE_OFFSET * corner2, c3);
col += w[2] * traceCone(origin - CONE_OFFSET * corner2, c4);
return col / 9.0;
}