diff --git a/resources/shaders/accumulation.hlsl b/resources/shaders/accumulation.hlsl index 17da9a1d..891e1f98 100644 --- a/resources/shaders/accumulation.hlsl +++ b/resources/shaders/accumulation.hlsl @@ -17,11 +17,7 @@ void main(uint3 DTid : SV_DispatchThreadID) float2 resolution; input.GetDimensions(resolution.x, resolution.y); - float2 uv = float2(DTid.xy) / resolution; - float gamma = 2.2; - float exposure = 1; - - float3 color = input[DTid.xy].rgb / (frame_idx); + float3 color = input[DTid.xy].rgb / (frame_idx + 1); output[DTid.xy] = float4(color, 1); } diff --git a/resources/shaders/deferred_composition.hlsl b/resources/shaders/deferred_composition.hlsl index ef0ec313..0f4f82a7 100644 --- a/resources/shaders/deferred_composition.hlsl +++ b/resources/shaders/deferred_composition.hlsl @@ -75,7 +75,7 @@ void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID) float3 sampled_environment_map = pref_env_map.SampleLevel(linear_sampler, reflect(-V, normal), roughness * MAX_REFLECTION_LOD); // Get irradiance - float irradiance = lerp( + float3 irradiance = lerp( irradiance_map.SampleLevel(linear_sampler, flipped_N, 0).xyz, screen_space_irradiance[screen_coord].xyz, is_path_tracer); diff --git a/resources/shaders/gi_util.hlsl b/resources/shaders/gi_util.hlsl new file mode 100644 index 00000000..0fa8e2f1 --- /dev/null +++ b/resources/shaders/gi_util.hlsl @@ -0,0 +1,170 @@ +#define M_PI 3.14159265358979 + +struct HitInfo +{ + float3 color; + unsigned int seed; + float3 origin; + unsigned int depth; +}; + +float4 TraceColorRay(float3 origin, float3 direction, unsigned int depth, unsigned int seed) +{ + if (depth >= MAX_RECURSION) + { + //return skybox.SampleLevel(s0, SampleSphericalMap(direction), 0); + return float4(0, 0, 0, 0); + } + + // Define a ray, consisting of origin, direction, and the min-max distance values + RayDesc ray; + ray.Origin = origin; + ray.Direction = direction; + ray.TMin = 0; + ray.TMax = 1.0e38f; + + HitInfo payload = { float3(1, 1, 1), seed, origin, depth }; + + // Trace the ray + TraceRay( + Scene, + RAY_FLAG_NONE, + ~0, // InstanceInclusionMask + 0, // RayContributionToHitGroupIndex + 0, // MultiplierForGeometryContributionToHitGroupIndex + 0, // miss shader index + ray, + payload); + + return float4(payload.color, 1); +} + +// NVIDIA's luminance function +inline float luminance(float3 rgb) +{ + return dot(rgb, float3(0.2126f, 0.7152f, 0.0722f)); +} + +// NVIDIA's probability function +float probabilityToSampleDiffuse(float3 difColor, float3 specColor) +{ + float lumDiffuse = max(0.01f, luminance(difColor.rgb)); + float lumSpecular = max(0.01f, luminance(specColor.rgb)); + return lumDiffuse / (lumDiffuse + lumSpecular); +} + +float3 ggxDirect(float3 hit_pos, float3 fN, float3 N, float3 V, float3 albedo, float metal, float roughness, unsigned int seed, unsigned int depth) +{ + // #################### GGX ##################### + uint light_count = lights[0].tid >> 2; + if (light_count < 1) return 0; + + int light_to_sample = min(int(nextRand(seed) * light_count), light_count - 1); + Light light = lights[light_to_sample]; + + float3 L = 0; + float max_light_dist = 0; + float3 light_intensity = 0; + { + // Calculate light properties + uint tid = light.tid & 3; + + //Light direction (constant with directional, position dependent with other) + L = (lerp(light.pos - hit_pos, light.dir, tid == light_type_directional)); + float light_dist = length(L); + L /= light_dist; + + //Spot intensity (only used with spot; but always calculated) + float min_cos = cos(light.ang); + float max_cos = lerp(min_cos, 1, 0.5f); + float cos_angle = dot(light.dir, L); + float spot_intensity = lerp(smoothstep(min_cos, max_cos, cos_angle), 1, tid != light_type_spot); + + //Attenuation & spot intensity (only used with point or spot) + float attenuation = lerp(1.0f - smoothstep(0, light.rad, light_dist), 1, tid == light_type_directional); + + light_intensity = (light.col * spot_intensity) * attenuation; + max_light_dist = lerp(light_dist, 100000, tid == light_type_directional); + } + + float3 H = normalize(V + L); + + // Shadow + float shadow_mult = float(light_count) * GetShadowFactor(hit_pos + (L * EPSILON), L, max_light_dist, depth, seed); + + // Compute some dot products needed for shading + float NdotV = saturate(dot(fN, V)); + float NdotL = saturate(dot(fN, L)); + float NdotH = saturate(dot(fN, H)); + float LdotH = saturate(dot(L, H)); + + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(NdotH, max(0.05, roughness)); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(NdotL, NdotV, max(0.05, roughness)); + // F = Fresnel factor (Reflectance depending on angle of incidence) + float3 F = F_Schlick(LdotH, metal, albedo); + //float3 F = F_ShlickSimple(metal, LdotH); + + float3 kS = F_SchlickRoughness(NdotV, metal, albedo, roughness); + float3 kD = (1.f - kS) * (1.0 - metal); + float3 spec = (D * F * G) / (4.0 * NdotV * NdotL + 0.001f); + + return shadow_mult * (light_intensity * (NdotL * spec + NdotL * albedo / M_PI)); +} + +float3 ggxIndirect(float3 hit_pos, float3 fN, float3 N, float3 V, float3 albedo, float metal, float roughness, unsigned int seed, unsigned int depth) +{ + // #################### GGX ##################### + float diffuse_probability = probabilityToSampleDiffuse(albedo, metal); + float choose_diffuse = (nextRand(seed) < diffuse_probability); + + // Diffuse lobe + if (choose_diffuse) + { + nextRand(seed); + const float3 rand_dir = getUniformHemisphereSample(seed, N); + float3 irradiance = TraceColorRay(hit_pos + (EPSILON * N), rand_dir, depth, seed); + + float3 lighting = shade_pixel(hit_pos, V, + albedo, + metal, + roughness, + fN, + seed, + depth+1); + + if (dot(N, rand_dir) <= 0.0f) irradiance = float3(0, 0, 0); + + return (lighting + (irradiance * albedo)) / diffuse_probability; + } + else + { + nextRand(seed); + float3 H = getGGXMicrofacet(seed, roughness, N); + + // ### BRDF ### + float3 L = normalize(2.f * dot(V, H) * H - V); + + float3 irradiance = TraceColorRay(hit_pos + (EPSILON * N), L, depth, seed); + if (dot(N, L) <= 0.0f) irradiance = float3(0, 0, 0); + + // Compute some dot products needed for shading + float NdotV = saturate(dot(N, V)); + float NdotL = saturate(dot(N, L)); + float NdotH = saturate(dot(N, H)); + float LdotH = saturate(dot(L, H)); + + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(NdotH, max(0.05, roughness)); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(NdotL, NdotV, max(0.05, roughness)); + // F = Fresnel factor (Reflectance depending on angle of incidence) + float3 F = F_Schlick(NdotH, metal, albedo); + + float3 spec = (D * F * G) / ((4.0 * NdotL * NdotV + 0.001f)); + float ggx_probability = D * NdotH / (4 * LdotH); + + return NdotL * irradiance * spec / (ggx_probability * (1.0f - diffuse_probability)); + } +} diff --git a/resources/shaders/path_tracer.hlsl b/resources/shaders/path_tracer.hlsl index 7b634bc7..fef21e68 100644 --- a/resources/shaders/path_tracer.hlsl +++ b/resources/shaders/path_tracer.hlsl @@ -3,6 +3,7 @@ #include "pbr_util.hlsl" #include "material_util.hlsl" #include "lighting.hlsl" +#include "gi_util.hlsl" struct Vertex { @@ -47,14 +48,6 @@ SamplerState s0 : register(s0); typedef BuiltInTriangleIntersectionAttributes MyAttributes; -struct HitInfo -{ - float3 color; - unsigned int seed; - float3 origin; - unsigned int depth; -}; - cbuffer CameraProperties : register(b0) { float4x4 inv_view; @@ -84,37 +77,6 @@ float3 HitWorldPosition() return WorldRayOrigin() + RayTCurrent() * WorldRayDirection(); } -float4 TraceColorRay(float3 origin, float3 direction, unsigned int depth, unsigned int seed) -{ - if (depth >= MAX_RECURSION) - { - //return skybox.SampleLevel(s0, SampleSphericalMap(direction), 0); - return float4(0, 0, 0, 0); - } - - // Define a ray, consisting of origin, direction, and the min-max distance values - RayDesc ray; - ray.Origin = origin; - ray.Direction = direction; - ray.TMin = EPSILON; - ray.TMax = 1.0e38f; - - HitInfo payload = { float3(1, 1, 1), seed, origin, depth }; - - // Trace the ray - TraceRay( - Scene, - RAY_FLAG_NONE, - ~0, // InstanceInclusionMask - 0, // RayContributionToHitGroupIndex - 0, // MultiplierForGeometryContributionToHitGroupIndex - 0, // miss shader index - ray, - payload); - - return float4(payload.color, 1); -} - float3 unpack_position(float2 uv, float depth) { // Get world space position @@ -123,78 +85,6 @@ float3 unpack_position(float2 uv, float depth) return (wpos.xyz / wpos.w).xyz; } -#define M_PI 3.14159265358979 - -// NVIDIA's luminance function -inline float luminance(float3 rgb) -{ - return dot(rgb, float3(0.2126f, 0.7152f, 0.0722f)); -} - -// NVIDIA's probability function -float probabilityToSampleDiffuse(float3 difColor, float3 specColor) -{ - float lumDiffuse = max(0.01f, luminance(difColor.rgb)); - float lumSpecular = max(0.01f, luminance(specColor.rgb)); - return lumDiffuse / (lumDiffuse + lumSpecular); -} - -float3 ggxIndirect(float3 hit_pos, float3 fN, float3 N, float3 V, float3 albedo, float metal, float roughness, unsigned int seed, unsigned int depth) -{ - // #################### GGX ##################### - float diffuse_probability = probabilityToSampleDiffuse(albedo, metal); - float choose_diffuse = (nextRand(seed) < diffuse_probability); - - // Diffuse lobe - if (choose_diffuse) - { - nextRand(seed); - const float3 rand_dir = getUniformHemisphereSample(seed, N); - float3 irradiance = TraceColorRay(hit_pos, rand_dir, depth, seed); - - float3 lighting = shade_pixel(hit_pos, V, - albedo, - metal, - roughness, - fN, - seed, - depth+1); - - if (dot(N, rand_dir) <= 0.0f) irradiance = float3(0, 0, 0); - - return (lighting + (irradiance * albedo)) / diffuse_probability; - } - else - { - nextRand(seed); - float3 H = getGGXMicrofacet(seed, roughness, N); - - // ### BRDF ### - float3 L = normalize(2.f * dot(V, H) * H - V); - - float3 irradiance = TraceColorRay(hit_pos, L, depth, seed); - if (dot(N, L) <= 0.0f) irradiance = float3(0, 0, 0); - - // Compute some dot products needed for shading - float NdotV = saturate(dot(N, V)); - float NdotL = saturate(dot(N, L)); - float NdotH = saturate(dot(N, H)); - float LdotH = saturate(dot(L, H)); - - // D = Normal distribution (Distribution of the microfacets) - float D = D_GGX(NdotH, roughness); - // G = Geometric shadowing term (Microfacets shadowing) - float G = G_SchlicksmithGGX(NdotL, NdotV, roughness); - // F = Fresnel factor (Reflectance depending on angle of incidence) - float3 F = F_Schlick(NdotH, metal, albedo); - - float3 spec = (D * F * G) / ((4.0 * NdotL * NdotV + 0.001f)); - float ggx_probability = D * NdotH / (4 * LdotH); - - return NdotL * irradiance * spec / (ggx_probability * (1.0f - diffuse_probability)); - } -} - [shader("raygeneration")] void RaygenEntry() { @@ -229,8 +119,9 @@ void RaygenEntry() nextRand(rand_seed); const float3 rand_dir = getUniformHemisphereSample(rand_seed, normal); const float cos_theta = cos(dot(rand_dir, normal)); - result = TraceColorRay(wpos, rand_dir, 0, rand_seed); - //result = ggxIndirect(wpos, normal, normal, V, albedo, metallic, roughness, rand_seed, 0); + result = TraceColorRay(wpos + (EPSILON * normal), rand_dir, 0, rand_seed); + //result += ggxIndirect(wpos, normal, normal, V, albedo, metallic, roughness, rand_seed, 0); + //result += ggxDirect(wpos, normal, normal, V, albedo, metallic, roughness, rand_seed, 0); result = clamp(result, 0, 100); @@ -327,46 +218,10 @@ void ReflectionHit(inout HitInfo payload, in MyAttributes attr) float3 fN = normalize(mul(output_data.normal, TBN)); fN = lerp(fN, -fN, dot(fN, V) < 0); - // Irradiance -#ifdef OLDSCHOOL - nextRand(payload.seed); - const float3 rand_dir = getUniformHemisphereSample(payload.seed, N); - const float cos_theta = cos(dot(rand_dir, normal)); - //float3 irradiance = TraceColorRay(hit_pos + (N * EPSILON), rand_dir, payload.depth + 1, payload.seed); - //float3 irradiance = (TraceColorRay(hit_pos + (N * EPSILON), rand_dir, payload.depth + 1, payload.seed) * cos_theta) * (albedo / PI); - float3 irradiance = (TraceColorRay(hit_pos, rand_dir, payload.depth + 1, payload.seed) * M_PI) * (1.0f / (2.0f * M_PI)); - - // Direct - float3 reflect_dir = reflect(-V, fN); - float3 reflection = TraceColorRay(hit_pos, reflect_dir, payload.depth + 1, payload.seed); - - const float3 F = F_SchlickRoughness(max(dot(fN, V), 0.0), - metal, - albedo, - roughness); - float3 kS = F; - float3 kD = 1.0 - kS; - kD *= 1.0 - metal; - - float3 lighting = shade_pixel(hit_pos, V, - albedo, - metal, - roughness, - fN, - payload.seed, - payload.depth+1); - float3 specular = (reflection) * F; - float3 diffuse = albedo * irradiance; - float3 ambient = (kD * diffuse + specular); - - payload.color = ambient + lighting; -#else - // #################### GGX ##################### nextRand(payload.seed); payload.color = ggxIndirect(hit_pos, fN, N, V, albedo, metal, roughness, payload.seed, payload.depth + 1); - -#endif + payload.color += ggxDirect(hit_pos, fN, N, V, albedo, metal, roughness, payload.seed, payload.depth + 1); } //Reflection skybox