浏览代码

Merge pull request #56 from EvgeniiG/master

Reduce noise related to IBL
/main
GitHub 8 年前
当前提交
58a746e5
共有 4 个文件被更改,包括 41 次插入50 次删除
  1. 12
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  2. 38
      Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
  3. 37
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl
  4. 4
      Assets/ScriptableRenderLoop/ShaderLibrary/Sampling.hlsl

12
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


PreLightData preLightData;
// TODO: check Eric idea about doing that when writting into the GBuffer (with our forward decal)
#if 0
preLightData.NdotV = GetShiftedNdotV(bsdfData.normalWS, V); // Note: May not work with speedtree...
#else
preLightData.NdotV = GetNdotV(bsdfData.normalWS, V);
#endif
preLightData.NdotV = GetShiftedNdotV(bsdfData.normalWS, V, false);
preLightData.ggxLambdaV = GetSmithJointGGXLambdaV(preLightData.NdotV, bsdfData.roughness);

// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NDotV) and use iblNormalWS
// into function like GetSpecularDominantDir(). However modified normal is just a hack. The goal is just to stretch a cubemap, no accuracy here.
// With this in mind and for performance reasons we chose to only use modified normal to calculate R.
// iblNdotV = GetNdotV(iblNormalWS, V);
// iblNdotV = GetShiftedNdotV(iblNormalWS, V), false);
}
GetPreIntegratedFGD(iblNdotV, bsdfData.perceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD);

float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

38
Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl


}
#ifndef INTRINSIC_CUBEMAP_FACE_ID
// TODO: implement this. Is the reference implementation of cubemapID provide by AMD the reverse of our ?
// TODO: implement this. Is the reference implementation of cubemapID provide by AMD the reverse of our ?
/*
float CubemapFaceID(float3 dir)
{

// 4 VGPR, 16 FR (12 FR, 1 QR), 2 scalar
// input [-infinity, infinity] and output [-PI/2, PI/2]
float FastATan(float x)
float FastATan(float x)
{
float t0 = FastATanPos(abs(x));
return (x < 0.0) ? -t0 : t0;

// various helper
//-----------------------------------------------------------------------------
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
// In this case this may cause weird artifact.
// GetNdotV return a 'valid' data
float GetNdotV(float3 N, float3 V)
{
return abs(dot(N, V)); // This abs allow to limit artifact
}
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
// In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.
// but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).
// Note: This code is not compatible with two sided lighting used in SpeedTree (TODO: investigate).
float GetShiftedNdotV(float3 N, float3 V)
// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) make use of two-sided lighting.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
// The amount we shift the normal toward the view vector is defined by the dot product.
float shiftAmount = dot(N, V);
N = shiftAmount < 0.0 ? N + V * (-shiftAmount + 1e-5f) : N;
N = normalize(N);
float NdotV = dot(N, V);
float limit = 1e-6;
if (!twoSided && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;
NdotV = limit;
}
return saturate(dot(N, V)); // TODO: this saturate should not be necessary here
return NdotV;
#endif // UNITY_COMMON_INCLUDED

37
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


// weightOverPdf = F(H) * G(V, L) * (L.H) / ((N.H) * (N.V))
// weightOverPdf = F(H) * 4 * (N.L) * V(V, L) * (L.H) / (N.H) with V(V, L) = G(V, L) / (4 * (N.L) * (N.V))
// Remind (L.H) == (V.H)
// F is apply outside the function
// F is apply outside the function
float TdotV = dot(tangentX, V);
float BdotV = dot(tangentY, V);
float TdotL = saturate(dot(tangentX, L));

// Ref: Listing 18 in "Moving Frostbite to PBR" + https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/
float4 IntegrateGGXAndDisneyFGD(float3 V, float3 N, float roughness, uint sampleCount)
{
float NdotV = saturate(dot(N, V));
float NdotV = GetShiftedNdotV(N, V, false);
float4 acc = float4(0.0, 0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

}
else // Prefiltered BRDF importance sampling
{
float NdotH = saturate(dot(N, H));
// Note: since L and V are symmetric around H, LdotH == VdotH
float LdotH = saturate(dot(L, H));
// Use pre - filtered importance sampling (i.e use lower mipmap
// level for fetching sample with low probability in order
// to reduce the variance ).
// ( Reference : GPU Gem3: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html)
// Use lower MIP-map levels for fetching samples with low probabilities
// in order to reduce the variance.
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
//
// pdf = D * NdotH * jacobian, where jacobian = 1.0 / (4* LdotH).
// Since we pre - integrate the result for normal direction ,
// N == V and then NdotH == LdotH . This is why the BRDF pdf
// can be simplifed from :
// pdf = D * NdotH /(4* LdotH ) to pdf = D / 4;
// Since L and V are symmetric around H, LdotH == VdotH.
// Since we pre-integrate the result for the normal direction,
// N == V and then NdotH == LdotH. Therefore, the BRDF's pdf
// can be simplified:
// pdf = D * NdotH / (4 * LdotH) = D * 0.25;
float pdf = D_GGXNoPI(NdotH, roughness) * NdotH / (4.0 * LdotH); // TODO: Check if divide PI is required here
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated to a sample
float NdotH = saturate(dot(N, H));
float pdf = D_GGX(NdotH, roughness) * 0.25;
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated with the sample
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated to a pixel of the cubemap
// Clamp is not necessary as the hardware will do it.
// mipLevel = Clamp(0.5f * log2(omegaS * invOmegaP), 0, mipmapcount);
mipLevel = 0.5 * log2(omegaS * invOmegaP); // Clamp is not necessary as the hardware will do it.
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated with the pixel of the cubemap
mipLevel = 0.5 * log2(omegaS * invOmegaP) + 1.0; // Clamp is not necessary as the hardware will do it
}
if (NdotL > 0.0f)

4
Assets/ScriptableRenderLoop/ShaderLibrary/Sampling.hlsl


// Ref: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
uint ReverseBits32(uint bits)
{
#if 0 // Shader model 5
#if 1 // Shader model 5
return reversebits(bits);
#else
bits = (bits << 16) | (bits >> 16);

Ns = UniformSampleSphere(u1, u2);
// Transform from unit sphere to world space
// Transform from unit sphere to world space
P = radius * Ns + localToWorld[3].xyz;
// pdf is inverse of area

正在加载...
取消
保存