浏览代码

Merge pull request #78 from EvgeniiG/master

PBS Fixes and Improvements
/main
GitHub 8 年前
当前提交
7cff9079
共有 5 个文件被更改,包括 61 次插入34 次删除
  1. 2
      Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl
  2. 1
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs
  3. 21
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.hlsl
  4. 25
      Assets/ScriptableRenderLoop/ShaderLibrary/BSDF.hlsl
  5. 46
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl

2
Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl


// EnvIndex can also be use to fetch in another array of struct (to atlas information etc...).
float4 SampleEnv(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod)
{
lod = min(lod, UNITY_SPECCUBE_LOD_STEPS);
// This code will be inlined as lightLoopContext is hardcoded in the light loop
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
{

1
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs


public void Build()
{
m_InitPreFGD = CreateEngineMaterial("Hidden/HDRenderPipeline/PreIntegratedFGD");
// TODO: switch to RGBA64 when it becomes available.
m_PreIntegratedFGD = new RenderTexture(128, 128, 0, RenderTextureFormat.ARGBHalf);
m_LtcGGXMatrix = LoadLUT(TextureFormat.RGBAHalf, s_LtcGGXMatrixData);

21
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.hlsl


// Maybe always using aniso maybe a win ?
if (bsdfData.materialId == MATERIALID_LIT_ANISO)
{
float TdotL = saturate(dot(bsdfData.tangentWS, L));
float BdotL = saturate(dot(bsdfData.bitangentWS, L));
// For anisotropy we must not saturate these values
float TdotH = dot(bsdfData.tangentWS, H);
float TdotL = dot(bsdfData.tangentWS, L);
float BdotH = dot(bsdfData.bitangentWS, H);
float BdotL = dot(bsdfData.bitangentWS, L);
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGXAnisoLambdaV( preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,

bsdfData.roughnessT, bsdfData.roughnessB);
#endif
// For anisotropy we must not saturate these values
float TdotH = dot(bsdfData.tangentWS, H);
float BdotH = dot(bsdfData.bitangentWS, H);
D = D_GGXAniso(TdotH, BdotH, NdotH, bsdfData.roughnessT, bsdfData.roughnessB);
}
else

float lightPdf = 0.0; // Pdf of the light sample
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
u = frac(u + randNum);
float4x4 localToWorld = float4x4(float4(lightData.right, 0.0), float4(lightData.up, 0.0), float4(lightData.forward, 0.0), float4(lightData.positionWS, 1.0));

for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
u = frac(u + randNum);
float3 L;
float NdotL;

for (uint i = 0; i < sampleCount; ++i)
{
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
u = frac(u + randNum);
float3 L;
float NdotL;

float3x3 localToWorld = GetLocalFrame(N, tangentX);
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
u = frac(u + randNum);
float VdotH;
float NdotL;

// GGX BRDF
if (bsdfData.materialId = MATERIALID_LIT_ANISO)
if (bsdfData.materialId == MATERIALID_LIT_ANISO)
{
ImportanceSampleAnisoGGX(u, V, N, tangentX, tangentY, bsdfData.roughnessT, bsdfData.roughnessB, NdotV, L, VdotH, NdotL, weightOverPdf);
}

25
Assets/ScriptableRenderLoop/ShaderLibrary/BSDF.hlsl


return PI * g;
}
// Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, p. 19, 29.
float G_MaskingSmithGGX(float NdotV, float VdotH, float roughness)
{
roughness = max(roughness, UNITY_MIN_ROUGHNESS);
// G1(V, H) = HeavisideStep(VdotH) / (1 + Λ(V)).
// Λ(V) = -0.5 + 0.5 * sqrt(1 + 1 / a²).
// a = 1 / (roughness * tan(theta)).
// 1 + Λ(V) = 0.5 + 0.5 * sqrt(1 + roughness² * tan²(theta)).
// tan²(theta) = (1 - cos²(theta)) / cos²(theta) = 1 / cos²(theta) - 1.
float hs = VdotH > 0.0 ? 1.0 : 0.0;
float a2 = roughness * roughness;
float z2 = NdotV * NdotV;
return hs / (0.5 + 0.5 * sqrt(1.0 + a2 * (1.0 / z2 - 1.0)));
}
// Ref: Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, p. 12.
float D_GGX_Visible(float NdotH, float NdotV, float VdotH, float roughness)
{
// Note that we pass 1.0 instead of 'VdotH' since the multiplication will already clamp.
return D_GGX(NdotH, roughness) * G_MaskingSmithGGX(NdotV, 1.0, roughness) * VdotH / NdotV;
}
// Ref: http://jcgt.org/published/0003/02/03/paper.pdf
float V_SmithJointGGX(float NdotL, float NdotV, float roughness)
{

46
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


void ImportanceSampleCosDir(float2 u,
float3x3 localToWorld,
out float3 L)
out float3 L,
out float NdotL)
float cosTheta = sqrt(saturate(1.0 - u.x));
float cosTheta = sqrt(1.0 - u.x);
L = SphericalToCartesian(phi, sinTheta, cosTheta);
L = mul(L, localToWorld);
float3 localL = SphericalToCartesian(phi, sinTheta, cosTheta);
NdotL = localL.z;
L = mul(localL, localToWorld);
}
void ImportanceSampleGGXDir(float2 u,

out float3 L,
out float NdotL,
out float NdotH,
out float VdotH,
bool VeqN = false)

VdotH = saturate(dot(localV, localH));
}
// Compute { L = reflect(-localV, localH) }
L = -localV + 2.0 * VdotH * localH;
// Compute { localL = reflect(-localV, localH) }
float3 localL = -localV + 2.0 * VdotH * localH;
NdotL = localL.z;
L = mul(L, localToWorld);
L = mul(localL, localToWorld);
}
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26

out float NdotL,
out float weightOverPdf)
{
ImportanceSampleCosDir(u, localToWorld, L);
NdotL = saturate(dot(localToWorld[2], L));
ImportanceSampleCosDir(u, localToWorld, L, NdotL);
// Importance sampling weight for each sample
// pdf = N.L / PI

out float NdotL,
out float weightOverPdf)
{
float3 H;
float NdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH);
NdotL = saturate(dot(localToWorld[2], L));
float NdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH);
// Importance sampling weight for each sample
// pdf = D(H) * (N.H) / (4 * (L.H))

// 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
// For anisotropy we must not saturate these values
float TdotL = saturate(dot(tangentX, L));
float BdotL = saturate(dot(tangentY, L));
float TdotL = dot(tangentX, L);
float BdotL = dot(tangentY, L);
float Vis = V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB);
weightOverPdf = 4.0 * Vis * NdotL * VdotH / NdotH;

// 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 = GetShiftedNdotV(N, V, false); // This fix some rare artifact at edge.
float NdotV = saturate(dot(N, V));
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);

u.x = lerp(u.x, 0.0, bias);
float3 L;
float NdotH, VdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH, true);
float NdotL = saturate(dot(N, L));
float NdotL, NdotH, VdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH, true);
float mipLevel;

正在加载...
取消
保存