#include "sh/common.hlsl" /* ========================== * * Root signature * ========================== */ #define ROOTSIG \ "RootConstants(num32BitConstants = 16, b0), " \ "DescriptorTable(SRV(t0, space = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " \ "DescriptorTable(SRV(t0, space = 1, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " \ "DescriptorTable(SRV(t0, space = 2, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " \ "DescriptorTable(UAV(u0, space = 3, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " ConstantBuffer g_constants : register(b0); Texture2D g_textures_float4[] : register(t0, space0); Texture2D g_textures_uint2[] : register(t0, space1); Texture3D g_noise_textures[] : register(t0, space2); RWTexture2D g_target_textures[]: register(u0, space3); struct cs_input { DECLS(uint3, SV_DispatchThreadID); }; /* ========================== * * Lighting * ========================== */ #define SAMPLES 64 #define MARCHES 16 #define AMBIENT float3(0, 0, 0) float rand_angle(uint2 pos, uint ray_index) { Texture3D noise_tex = g_noise_textures[SH_BLUE_NOISE_TEX_ID]; int3 noise_coord = int3(1, 1, 1); noise_coord += int3(pos.xy, ray_index); // noise_coord.xyz += g_constants.frame_seed.xyz; noise_coord.xy -= g_constants.camera_offset; uint noise = noise_tex[noise_coord % uint3(SH_BLUE_NOISE_TEX_WIDTH, SH_BLUE_NOISE_TEX_HEIGHT, SH_BLUE_NOISE_TEX_DEPTH)]; return ((float)noise / (float)0xFFFF) * TAU; } INLINE float3 get_light_in_dir(uint2 ray_start, float2 ray_dir) { Texture2D flood_tex = g_textures_uint2[g_constants.emittance_flood_tex_urid]; Texture2D emittance_tex = g_textures_float4[g_constants.emittance_tex_urid]; float3 result = AMBIENT; float2 at_float = ray_start; uint2 at_uint = ray_start; for (uint i = 0; i < MARCHES; ++i) { uint2 flood = flood_tex[at_uint]; float2 dist_vec = at_float - (float2)flood; float dist = length(dist_vec); if (dist < 1) { result = emittance_tex[flood].rgb; break; } else { at_float += ray_dir * dist; at_uint = round(at_float); if (at_uint.x < 0 || at_uint.x >= g_constants.tex_width || at_uint.y < 0 || at_uint.y >= g_constants.tex_height) { /* Ambient lighting (ray hit edge of screen) */ break; } } } return result; } INLINE float3 get_light_at_pos(uint2 pos) { float3 result = 0; for (uint i = 0; i < SAMPLES; ++i) { float angle = rand_angle(pos, i); float2 dir = float2(cos(angle), sin(angle)); float3 light_in_dir = get_light_in_dir(pos, dir); result += light_in_dir; } result /= SAMPLES; return result; } /* ========================== * * Entry point * ========================== */ [numthreads(8, 8, 1)] SH_ENTRY(ROOTSIG) void cs(struct cs_input input) { uint2 id = input.SV_DispatchThreadID.xy; if (id.x < g_constants.tex_width && id.y < g_constants.tex_height) { Texture2D albedo_tex = g_textures_float4[g_constants.albedo_tex_urid]; Texture2D read_tex = g_textures_float4[g_constants.read_tex_urid]; RWTexture2D target_tex = g_target_textures[g_constants.target_tex_urid]; float4 color = float4(1, 1, 1, 1); /* Apply albedo */ color *= albedo_tex[id]; /* Apply lighting */ color.rgb *= get_light_at_pos(id); /* Apply temporal accumulation */ float hysterisis = 0; // hysterisis = 0.2; // hysterisis = 0.9; color.rgb = lerp(color.rgb, read_tex[id].rgb, hysterisis); target_tex[id] = color; } }