浏览代码

Clean up the sampling code

/main
Evgenii Golubev 8 年前
当前提交
e3de02f6
共有 1 个文件被更改,包括 71 次插入67 次删除
  1. 138
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl

138
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


return saturate(mipmapLevel / UNITY_SPECCUBE_LOD_STEPS);
}
// Ref: See "Moving Frostbite to PBR" Listing 22
// This formulation is for GGX only (with smith joint visibility or regular)
float3 GetSpecularDominantDir(float3 N, float3 R, float roughness)
{
float a = 1.0 - roughness;
float lerpFactor = a * (sqrt(a) + roughness);
// The result is not normalized as we fetch in a cubemap
return lerp(N, R, lerpFactor);
}
//-----------------------------------------------------------------------------
// Anisotropic image based lighting
//-----------------------------------------------------------------------------
// To simulate the streching of highlight at grazing angle for IBL we shrink the roughness
// which allow to fake an anisotropic specular lobe.
// Ref: http://www.frostbite.com/2015/08/stochastic-screen-space-reflections/ - slide 84
float AnisotropicStrechAtGrazingAngle(float roughness, float perceptualRoughness, float NdotV)
{
return roughness * lerp(saturate(NdotV * 2.0), 1.0, perceptualRoughness);
}
float3 SphericalToCartesian(float phi, float sinTheta, float cosTheta)
float3 SphericalToCartesian(float phi, float cosTheta)
float sinTheta = sqrt(saturate(1.0 - cosTheta * cosTheta));
return float3(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta);
}

float3 TransformGLtoDX(float x, float y, float z)
{
return float3(x, z, y);
}
float3 TransformGLtoDX(float3 v)
{
return v.xzy;

float3 ConvertEquiarealToCubemap(float u, float v)
{
// The equiareal mapping is defined as follows:
// phi = TWO_PI * (1.0 - u)
// cos(theta) = 1.0 - 2.0 * v
// sin(theta) = sqrt(1.0 - cos^2(theta)) = 2.0 * sqrt(v - v * v)
float sinTheta = 2.0 * sqrt(v - v * v);
return TransformGLtoDX(SphericalToCartesian(phi, sinTheta, cosTheta));
}
// Ref: See "Moving Frostbite to PBR" Listing 22
// This formulation is for GGX only (with smith joint visibility or regular)
float3 GetSpecularDominantDir(float3 N, float3 R, float roughness)
{
float a = 1.0 - roughness;
float lerpFactor = a * (sqrt(a) + roughness);
// The result is not normalized as we fetch in a cubemap
return lerp(N, R, lerpFactor);
}
//-----------------------------------------------------------------------------
// Anisotropic image based lighting
//-----------------------------------------------------------------------------
// To simulate the streching of highlight at grazing angle for IBL we shrink the roughness
// which allow to fake an anisotropic specular lobe.
// Ref: http://www.frostbite.com/2015/08/stochastic-screen-space-reflections/ - slide 84
float AnisotropicStrechAtGrazingAngle(float roughness, float perceptualRoughness, float NdotV)
{
return roughness * lerp(saturate(NdotV * 2.0), 1.0, perceptualRoughness);
return TransformGLtoDX(SphericalToCartesian(phi, cosTheta));
}
// ----------------------------------------------------------------------------

void ImportanceSampleCosDir(float2 u,
// Performs uniform sampling of the unit disk.
// Ref: PBRT v3, p. 777.
float2 SampleDiskUniform(float2 u)
{
float r = sqrt(u.x);
float phi = TWO_PI * u.y;
float sinPhi, cosPhi;
sincos(phi, sinPhi, cosPhi);
return r * float2(cosPhi, sinPhi);
}
// Performs cosine-weighted sampling of the hemisphere.
// Ref: PBRT v3, p. 780.
void SampleHemisphereCosine(float2 u,
// Cosine sampling - ref: http://www.rorydriscoll.com/2009/01/07/better-sampling/
float cosTheta = sqrt(1.0 - u.x);
float sinTheta = sqrt(u.x);
float phi = TWO_PI * u.y;
float3 localL;
// Since we don't really care about the area distortion,
// we substitute uniform disk sampling for the concentric one.
localL.xy = SampleDiskUniform(u);
float3 localL = SphericalToCartesian(phi, sinTheta, cosTheta);
// Project the point from the disk onto the hemisphere.
localL.z = sqrt(1.0 - u.x);
NdotL = localL.z;

void ImportanceSampleGGXDir(float2 u,
float3 V,
float3x3 localToWorld,
float roughness,
out float3 L,
out float NdotL,
out float NdotH,
out float VdotH,
bool VeqN = false)
void SampleGGXDir(float2 u,
float3 V,
float3x3 localToWorld,
float roughness,
out float3 L,
out float NdotL,
out float NdotH,
out float VdotH,
bool VeqN = false)
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
float3 localH = SphericalToCartesian(phi, sinTheta, cosTheta);
float3 localH = SphericalToCartesian(phi, cosTheta);
NdotH = cosTheta;

}
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26
void ImportanceSampleAnisoGGXDir( float2 u,
float3 V,
float3 N,
float3 tangentX,
float3 tangentY,
float roughnessT,
float roughnessB,
out float3 H,
out float3 L)
void SampleAnisoGGXDir(float2 u,
float3 V,
float3 N,
float3 tangentX,
float3 tangentY,
float roughnessT,
float roughnessB,
out float3 H,
out float3 L)
// Local to world
// H = tangentX * H.x + tangentY * H.y + N * H.z;
// Convert sample from half angle to incident angle
L = 2.0 * saturate(dot(V, H)) * H - V;
}

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

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

out float weightOverPdf)
{
float3 H;
ImportanceSampleAnisoGGXDir(u, V, N, tangentX, tangentY, roughnessT, roughnessB, H, L);
SampleAnisoGGXDir(u, V, N, tangentX, tangentY, roughnessT, roughnessB, H, L);
float NdotH = saturate(dot(N, H));
// Note: since L and V are symmetric around H, LdotH == VdotH

float3 L;
float NdotL, NdotH, VdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH, true);
SampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH, true);
float mipLevel;

正在加载...
取消
保存