浏览代码

Orthonormalize TBN

/main
Evgenii Golubev 8 年前
当前提交
96c60309
共有 9 个文件被更改,包括 84 次插入101 次删除
  1. 5
      Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/Resources/Deferred.shader
  2. 5
      Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute
  3. 62
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.hlsl
  4. 18
      Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl
  5. 12
      Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderPass/ShaderPassGBuffer.hlsl
  6. 9
      Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl
  7. 23
      Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
  8. 24
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl
  9. 27
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl

5
Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/Resources/Deferred.shader


float3 bakeDiffuseLighting;
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting);
// We do not saturate for double-sided lighting.
// For single-sided lighting, the normal has already been adjusted during the G-buffer pass.
float NdotV = dot(bsdfData.normalWS, V);
bool twoSided = false;
float NdotV = GetShiftedNdotV(bsdfData.normalWS, V, twoSided);
PreLightData preLightData = GetPreLightData(V, NdotV, posInput, bsdfData);

5
Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute


float3 bakeDiffuseLighting;
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting);
// We do not saturate for double-sided lighting.
// For single-sided lighting, the normal has already been adjusted during the G-buffer pass.
float NdotV = dot(bsdfData.normalWS, V);
bool twoSided = false;
float NdotV = GetShiftedNdotV(bsdfData.normalWS, V, twoSided);
PreLightData preLightData = GetPreLightData(V, NdotV, posInput, bsdfData);

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


bsdfData.diffuseColor = surfaceData.baseColor * (1.0 - surfaceData.metallic);
bsdfData.fresnel0 = lerp(float3(surfaceData.specular, surfaceData.specular, surfaceData.specular), surfaceData.baseColor, surfaceData.metallic);
bsdfData.tangentWS = surfaceData.tangentWS;
bsdfData.bitangentWS = cross(surfaceData.normalWS, surfaceData.tangentWS);
bsdfData.tangentWS = surfaceData.tangentWS;
bsdfData.bitangentWS = cross(surfaceData.normalWS, surfaceData.tangentWS);
ConvertAnisotropyToRoughness(bsdfData.roughness, surfaceData.anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.anisotropy = surfaceData.anisotropy;

bsdfData.fresnel0 = lerp(float3(specular, specular, specular), baseColor, metallic);
bsdfData.tangentWS = UnpackNormalOctEncode(float2(inGBuffer2.rg * 2.0 - 1.0));
// TODO: Do we need to orthonormalize here, IIRC Eric say that we should
bsdfData.bitangentWS = cross(bsdfData.normalWS, bsdfData.tangentWS);
ConvertAnisotropyToRoughness(bsdfData.roughness, anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.anisotropy = anisotropy;

P1 -= positionWS;
P2 -= positionWS;
// Construct an orthonormal basis (local coordinate system) around N.
// TODO: it could be stored in PreLightData. All LTC lights compute it more than once!
// Also consider using 'bsdfData.tangentWS', 'bsdfData.bitangentWS', 'bsdfData.normalWS'.
// Construct a view-dependent orthonormal basis around N.
// TODO: it could be stored in PreLightData, since all LTC lights compute it more than once.
float3x3 basis;
basis[0] = normalize(V - bsdfData.normalWS * preLightData.NdotV);
basis[1] = normalize(cross(bsdfData.normalWS, basis[0]));

// ----------------------------------------------------------------------------
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateLambertIBLRef( LightLoopContext lightLoopContext,
EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 4096)
float3 IntegrateLambertIBLRef(LightLoopContext lightLoopContext,
float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 4096)
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float3x3 localToWorld = float3x3(bsdfData.tangentWS, bsdfData.bitangentWS, bsdfData.normalWS);
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
for (uint i = 0; i < sampleCount; ++i)
{

}
float3 IntegrateDisneyDiffuseIBLRef(LightLoopContext lightLoopContext,
float3 V, EnvLightData lightData, BSDFData bsdfData,
float3 V, PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData,
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
// This function call may modify the normal.
float NdotV = GetShiftedNdotV(N, V, false);
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float3x3 localToWorld = float3x3(bsdfData.tangentWS, bsdfData.bitangentWS, bsdfData.normalWS);
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
for (uint i = 0; i < sampleCount; ++i)
{

float LdotH = dot(L, H);
// Note: we call DisneyDiffuse that require to multiply by Albedo / PI. Divide by PI is already taken into account
// in weightOverPdf of ImportanceSampleLambert call.
float disneyDiffuse = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
float disneyDiffuse = DisneyDiffuse(preLightData.NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
// diffuse Albedo is apply here as describe in ImportanceSampleLambert function
float4 val = SampleEnv(lightLoopContext, lightData.envIndex, L, 0);

}
// Ref: Moving Frostbite to PBR (Appendix A)
float3 IntegrateSpecularGGXIBLRef( LightLoopContext lightLoopContext,
float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 4096)
float3 IntegrateSpecularGGXIBLRef(LightLoopContext lightLoopContext,
float3 V, PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 4096)
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
// This function call may modify the normal.
float NdotV = GetShiftedNdotV(N, V, false);
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float3x3 localToWorld = float3x3(bsdfData.tangentWS, bsdfData.bitangentWS, bsdfData.normalWS);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

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

#ifdef LIT_DISPLAY_REFERENCE_IBL
specularLighting = IntegrateSpecularGGXIBLRef(lightLoopContext, V, lightData, bsdfData);
specularLighting = IntegrateSpecularGGXIBLRef(lightLoopContext, V, preLightData, lightData, bsdfData);
diffuseLighting = IntegrateLambertIBLRef(lightData, bsdfData);
diffuseLighting = IntegrateLambertIBLRef(lightData, V, bsdfData);
diffuseLighting = IntegrateDisneyDiffuseIBLRef(lightLoopContext, V, lightData, bsdfData);
diffuseLighting = IntegrateDisneyDiffuseIBLRef(lightLoopContext, V, preLightData, lightData, bsdfData);
#endif
*/
diffuseLighting = float3(0.0, 0.0, 0.0);

specularLighting *= bsdfData.specularOcclusion;
diffuseLighting = float3(0.0, 0.0, 0.0);
#endif
#endif

18
Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl


UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);
SurfaceData surfaceData;
BuiltinData builtinData;
GetSurfaceAndBuiltinData(input, V, posInput, surfaceData, builtinData);
SurfaceData surfaceData;
BuiltinData builtinData;
GetSurfaceAndBuiltinData(input, V, posInput, surfaceData, builtinData);
BSDFData bsdfData = ConvertSurfaceDataToBSDFData(surfaceData);
bool twoSided = false;
// This will always produce the correct 'NdotV' value, but potentially
// reduce the length of the normal at edges of geometry.
float NdotV = GetShiftedNdotV(surfaceData.normalWS, V, twoSided);
bool twoSided = false;
float NdotV = GetShiftedNdotV(bsdfData.normalWS, V, twoSided);
// Orthonormalize the basis vectors using the Gram-Schmidt process.
surfaceData.normalWS = normalize(surfaceData.normalWS);
surfaceData.tangentWS = normalize(surfaceData.tangentWS - dot(surfaceData.tangentWS, surfaceData.normalWS));
BSDFData bsdfData = ConvertSurfaceDataToBSDFData(surfaceData);
PreLightData preLightData = GetPreLightData(V, NdotV, posInput, bsdfData);

12
Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderPass/ShaderPassGBuffer.hlsl


BuiltinData builtinData;
GetSurfaceAndBuiltinData(input, V, posInput, surfaceData, builtinData);
BSDFData bsdfData = ConvertSurfaceDataToBSDFData(surfaceData);
bool twoSided = false;
// This will always produce the correct 'NdotV' value, but potentially
// reduce the length of the normal at edges of geometry.
float NdotV = GetShiftedNdotV(surfaceData.normalWS, V, twoSided);
bool twoSided = false;
float NdotV = GetShiftedNdotV(bsdfData.normalWS, V, twoSided);
// Orthonormalize the basis vectors using the Gram-Schmidt process.
surfaceData.normalWS = normalize(surfaceData.normalWS);
surfaceData.tangentWS = normalize(surfaceData.tangentWS - dot(surfaceData.tangentWS, surfaceData.normalWS));
BSDFData bsdfData = ConvertSurfaceDataToBSDFData(surfaceData);
PreLightData preLightData = GetPreLightData(V, NdotV, posInput, bsdfData);

9
Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl


{
// 1. ClipQuadToHorizon
// detect clipping config
// detect clipping config
uint config = 0;
if (L[0].z > 0) config += 1;
if (L[1].z > 0) config += 2;

// For polygonal lights.
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, bool twoSided, float3x3 invM)
{
// Construct local orthonormal basis around N, aligned with N
// TODO: it could be stored in PreLightData. All LTC lights compute it more than once!
// Also consider using 'bsdfData.tangentWS', 'bsdfData.bitangentWS', 'bsdfData.normalWS'.
// Construct a view-dependent orthonormal basis around N.
// TODO: it could be stored in PreLightData, since all LTC lights compute it more than once.
float3x3 basis;
basis[0] = normalize(V - N * NdotV);
basis[1] = normalize(cross(N, basis[0]));

// 'normal' is the direction orthogonal to the tangent. It is the shortest vector between
// the shaded point and the line, pointing away from the shaded point.
float LineIrradiance(float l1, float l2, float3 normal, float3 tangent)
{
{
float d = length(normal);
float l1rcpD = l1 * rcp(d);
float l2rcpD = l2 * rcp(d);

23
Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl


posInput.positionWS += V * depthOffsetVS;
}
//-----------------------------------------------------------------------------
// various helper
//-----------------------------------------------------------------------------
// 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 double-sided lighting.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
{
float NdotV = dot(N, V);
float limit = 1e-4;
if (!twoSided && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;
NdotV = limit;
}
return NdotV;
}
#endif // UNITY_COMMON_INCLUDED

24
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


}
//-----------------------------------------------------------------------------
// Get local frame
// Helper functions
// Generates an orthonormal basis from two orthogonal unit vectors.
float3x3 GetLocalFrame(float3 localZ, float3 localX)
// 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 double-sided lighting.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
float3 localY = cross(localZ, localX);
float NdotV = dot(N, V);
float limit = 1e-4;
return float3x3(localX, localY, localZ);
if (!twoSided && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;
NdotV = limit;
}
return NdotV;
}
// Generates an orthonormal basis from a unit vector.

float3 localX = normalize(cross(upVector, localZ));
float3 localY = cross(localZ, localX);
return GetLocalFrame(localZ, localX);
return float3x3(localX, localY, localZ);
}
// TODO: test

27
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


}
// weightOverPdf return the weight (without the Fresnel term) over pdf. Fresnel term must be apply by the caller.
void ImportanceSampleAnisoGGX(
float2 u,
float3 V,
float3 N,
float3 tangentX,
float3 tangentY,
float roughnessT,
float roughnessB,
float NdotV,
out float3 L,
out float VdotH,
out float NdotL,
out float weightOverPdf)
void ImportanceSampleAnisoGGX(float2 u,
float3 V,
float3x3 localToWorld,
float roughnessT,
float roughnessB,
float NdotV,
out float3 L,
out float VdotH,
out float NdotL,
out float weightOverPdf)
float3 tangentX = localToWorld[0];
float3 tangentY = localToWorld[1];
float3 N = localToWorld[2];
float3 H;
SampleAnisoGGXDir(u, V, N, tangentX, tangentY, roughnessT, roughnessB, H, L);

正在加载...
取消
保存