Files
armorpaint/paint/shaders/ssao_pass.kong
T
2025-09-20 23:20:39 +02:00

164 lines
3.6 KiB
Plaintext

#[set(everything)]
const constants: {
invP: float4x4;
P: float4x4;
V3: float3x3;
camera_proj: float2;
};
#[set(everything)]
const sampler_linear: sampler;
#[set(everything)]
const gbufferD: tex2d;
#[set(everything)]
const gbuffer0: tex2d;
const max_steps: float = 30.0;
const ray_step: float = 0.005;
struct vert_in {
pos: float2;
}
struct vert_out {
pos: float4;
tex: float2;
view_ray: float3;
}
fun ssao_pass_vert(input: vert_in): vert_out {
var output: vert_out;
output.tex = input.pos.xy * 0.5 + 0.5;
output.tex.y = 1.0 - output.tex.y;
output.pos = float4(input.pos.xy, 0.0, 1.0);
// NDC (at the back of cube)
var v: float4 = float4(input.pos.x, input.pos.y, 1.0, 1.0);
v = constants.invP * v;
output.view_ray = float3(v.xy / v.z, 1.0);
return output;
}
fun get_projected_coord(hit_coord: float3): float2 {
var projected_coord: float4 = constants.P * float4(hit_coord, 1.0);
projected_coord.xy = projected_coord.xy / projected_coord.w;
projected_coord.xy = projected_coord.xy * 0.5 + 0.5;
projected_coord.y = 1.0 - projected_coord.y;
return projected_coord.xy;
}
fun get_pos_view(view_ray: float3, depth: float): float3 {
var linear_depth: float = constants.camera_proj.y / (constants.camera_proj.x - depth);
return view_ray * linear_depth;
}
fun get_delta_depth(hit_coord: float3): float {
var coord: float2 = get_projected_coord(hit_coord);
if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0) {
return 1000.0;
}
var depth: float = sample_lod(gbufferD, sampler_linear, coord, 0.0).r;
var linear_depth: float = constants.camera_proj.y / (constants.camera_proj.x - depth);
return linear_depth - hit_coord.z;
}
fun ray_cast(dir: float3, vpos: float3): float {
var n_dir: float3 = normalize(dir);
var step_vec: float3 = n_dir * ray_step;
var hit_coord: float3 = vpos;
var t: float = 0.0;
var i: int = 0;
while (i < int(max_steps)) {
hit_coord += step_vec;
t += ray_step;
var delta: float = get_delta_depth(hit_coord);
if (delta > 0.0 && delta < 0.2) {
return t;
}
if (t > 2.0) {
return 0.15; // max_radius;
}
i += 1;
}
return 0.15; // max_radius;
}
fun tangent(n: float3): float3 {
var t1: float3 = cross(n, float3(0.0, 0.0, 1.0));
var t2: float3 = cross(n, float3(0.0, 1.0, 0.0));
if (length(t1) > length(t2)) {
return normalize(t1);
}
return normalize(t2);
}
fun octahedron_wrap(v: float2): float2 {
var a: float2;
if (v.x >= 0.0) {
a.x = 1.0;
}
else {
a.x = -1.0;
}
if (v.y >= 0.0) {
a.y = 1.0;
}
else {
a.y = -1.0;
}
var r: float2;
r.x = abs(v.y);
r.y = abs(v.x);
r.x = 1.0 - r.x;
r.y = 1.0 - r.y;
return r * a;
}
fun ssao_pass_frag(input: vert_out): float {
var g0: float4 = sample_lod(gbuffer0, sampler_linear, input.tex, 0.0);
var d: float = sample_lod(gbufferD, sampler_linear, input.tex, 0.0).r;
var enc: float2 = g0.rg;
var n: float3;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
if (n.z >= 0.0) {
n.x = enc.x;
n.y = enc.y;
}
else {
var f2: float2 = octahedron_wrap(enc.xy);
n.x = f2.x;
n.y = f2.y;
}
n = normalize(constants.V3 * n);
var vpos: float3 = get_pos_view(input.view_ray, d);
var o1: float3 = tangent(n);
var o2: float3 = cross(o1, n);
var c1: float3 = 0.5 * (o1 + o2);
var c2: float3 = 0.5 * (o1 - o2);
var col: float = ray_cast(lerp3(n, o1, 0.5), vpos);
col += ray_cast(lerp3(n, -o1, 0.5), vpos);
col += ray_cast(lerp3(n, o2, 0.5), vpos);
col += ray_cast(lerp3(n, -o2, 0.5), vpos);
col += ray_cast(lerp3(n, c1, 0.5), vpos);
col += ray_cast(lerp3(n, -c1, 0.5), vpos);
col += ray_cast(lerp3(n, c2, 0.5), vpos);
col += ray_cast(lerp3(n, -c2, 0.5), vpos);
return col * 0.5;
}
#[pipe]
struct pipe {
vertex = ssao_pass_vert;
fragment = ssao_pass_frag;
}