Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Direct GI #272

Merged
merged 2 commits into from May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 1 addition & 5 deletions resources/shaders/accumulation.hlsl
Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you divide by frame_idx? Means the color would be divided by 1, then 2, then 3?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I guess the var name is correct, but frame_idx is also referenced to as the current render index


output[DTid.xy] = float4(color, 1);
}
2 changes: 1 addition & 1 deletion resources/shaders/deferred_composition.hlsl
Expand Up @@ -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);
Expand Down
170 changes: 170 additions & 0 deletions 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));
}
}
155 changes: 5 additions & 150 deletions resources/shaders/path_tracer.hlsl
Expand Up @@ -3,6 +3,7 @@
#include "pbr_util.hlsl"
#include "material_util.hlsl"
#include "lighting.hlsl"
#include "gi_util.hlsl"

struct Vertex
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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()
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down