LumixEngine/data/pipelines/sss.shd
2023-09-22 13:52:15 +02:00

85 lines
No EOL
2.7 KiB
Text

include "pipelines/common.glsl"
compute_shader [[
layout(std140, binding = 4) uniform Data {
vec2 u_size;
float u_max_steps;
float u_stride;
};
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout (binding = 0) uniform sampler2D u_depth;
layout (r8, binding = 1) uniform image2D u_sss_buffer;
// based on http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html
void raycast(vec3 csOrig, vec3 csDir, float stride, float jitter, ivec2 ip0) {
vec3 csEndPoint = csOrig + abs(csOrig.z * 0.1) * csDir;
vec4 H0 = Global.projection * vec4(csOrig, 1);
vec4 H1 = Global.projection * vec4(csEndPoint, 1);
float k0 = 1 / H0.w, k1 = 1 / H1.w;
vec2 P0 = toScreenUV(H0.xy * k0 * 0.5 + 0.5) * u_size;
vec2 P1 = toScreenUV(H1.xy * k1 * 0.5 + 0.5) * u_size;
vec2 delta = P1 - P0;
bool permute = abs(delta.x) < abs(delta.y);
if (permute) {
P0 = P0.yx;
P1 = P1.yx;
delta = delta.yx;
}
float stepDir = sign(delta.x);
float invdx = stepDir / delta.x;
float dk = ((k1 - k0) * invdx) * stride;
vec2 dP = (vec2(stepDir, delta.y * invdx)) * stride;
vec2 P = P0;
float k = k0;
uint max_steps = uint(min(abs(P1.x - P0.x), u_max_steps)) >> 2;
for (uint j = 0; j < 4; ++j) {
P += dP * jitter;
k += dk * jitter;
for (uint i = 0; i < max_steps; ++i) {
float rayZFar = 1 / k;
vec2 p = permute ? P.yx : P;
if (any(lessThan(p, vec2(0)))) break;
if (any(greaterThan(p, vec2(u_size)))) break;
float depth = texture(u_depth, p / u_size).x;
depth = toLinearDepth(Global.inv_projection, depth);
float dif = rayZFar - depth;
if (dif < depth * 0.02 && dif > 1e-3) {
imageStore(u_sss_buffer, ip0, vec4(0));
return;
}
P += dP;
k += dk;
}
P -= dP;
k -= dk;
dP *= 2;
dk *= 2;
}
imageStore(u_sss_buffer, ip0, vec4(1));
}
void main() {
vec2 inv_size = 1 / u_size;
vec2 uv = vec2(gl_GlobalInvocationID.xy) * inv_size;
vec3 p = getViewPosition(u_depth, Global.inv_view_projection, uv);
vec4 o = Global.view * vec4(p, 1);
vec3 d = mat3(Global.view) * Global.light_dir.xyz;
float rr = random(vec2(gl_GlobalInvocationID.xy) + 0.1 * Global.time);
raycast(o.xyz, d.xyz, u_stride, rr, ivec2(gl_GlobalInvocationID.xy));
}
]]