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

Commit

Permalink
Merge pull request #272 from TeamWisp/feature_gi
Browse files Browse the repository at this point in the history
Direct GI
  • Loading branch information
VZout committed May 7, 2019
2 parents c43ddd5 + 1619f83 commit eef058a
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 156 deletions.
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);

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

0 comments on commit eef058a

Please sign in to comment.