浏览代码

Merge pull request #934 from Unity-Technologies/Improve-normal-shading

Improve normal shading
/main
GitHub 6 年前
当前提交
3e753c62
共有 7 个文件被更改,包括 37 次插入35 次删除
  1. 6
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl
  2. 2
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/ImageBasedLighting.hlsl
  3. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/LayeredLit/LayeredLitDataDisplacement.hlsl
  4. 50
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  5. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitData.hlsl
  6. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitDataDisplacement.hlsl
  7. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitReference.hlsl

6
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl


// Helper functions
//-----------------------------------------------------------------------------
// Ref: "Crafting a Next-Gen Material Pipeline for The Order: 1886".
float ClampNdotV(float NdotV)
{
return max(NdotV, 0.0001);
}
// Inputs: normalized normal and view vectors.
// Outputs: front-facing normal, and the new non-negative value of the cosine of the view angle.
// Important: call Orthonormalize() on the tangent and recompute the bitangent afterwards.

2
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/ImageBasedLighting.hlsl


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

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/LayeredLit/LayeredLitDataDisplacement.hlsl


// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign. { height = -height + 1 }.
float verticalDisplacement = maxHeight - height * maxHeight;
return verticalDisplacement / max(NdotV, 0.001);
return verticalDisplacement / ClampNdotV(NdotV);
#else
return 0.0;
#endif

50
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


// Precomputed lighting data to send to the various lighting functions
struct PreLightData
{
// General
float clampNdotV; // clamped NdotV
float NdotV; // Could be negative due to normal mapping, use ClampNdotV()
// GGX
float partLambdaV;

float3 iblR; // Dominant specular direction, used for IBL in EvaluateBSDF_Env()
float iblPerceptualRoughness;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal (6x VGPRs)
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse (4x VGPRs)
float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal (6x VGPRs)
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse (4x VGPRs)
float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float ltcMagnitudeDiffuse;
float3 ltcMagnitudeFresnel;

float coatIblF; // Fresnel term for view vector
float3x3 ltcTransformCoat; // Inverse transformation for GGX (4x VGPRs)
float coatIblF; // Fresnel term for view vector
float3x3 ltcTransformCoat; // Inverse transformation for GGX (4x VGPRs)
float3 transparentRefractV; // refracted view vector after exiting the shape
float3 transparentPositionWS; // start of the refracted ray after exiting the shape
float3 transparentTransmittance; // transmittance due to absorption
float transparentSSMipLevel; // mip level of the screen space gaussian pyramid for rough refraction
float3 transparentRefractV; // refracted view vector after exiting the shape
float3 transparentPositionWS; // start of the refracted ray after exiting the shape
float3 transparentTransmittance; // transmittance due to absorption
float transparentSSMipLevel; // mip level of the screen space gaussian pyramid for rough refraction
};
PreLightData GetPreLightData(float3 V, PositionInputs posInput, BSDFData bsdfData)

float3 N = bsdfData.normalWS;
float NdotV = saturate(dot(N, V));
preLightData.clampNdotV = NdotV; // Caution: The handling of edge cases where N is directed away from the screen is handled during Gbuffer/forward pass, so here do nothing
preLightData.NdotV = dot(N, V);
float NdotV = ClampNdotV(preLightData.NdotV);
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
{

preLightData.ltcTransformSpecular._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
// Construct a right-handed view-dependent orthogonal basis around the normal
preLightData.orthoBasisViewNormal[0] = normalize(V - N * NdotV);
preLightData.orthoBasisViewNormal[0] = normalize(V - N * preLightData.NdotV); // Do not clamp NdotV here
preLightData.orthoBasisViewNormal[2] = N;
preLightData.orthoBasisViewNormal[1] = cross(preLightData.orthoBasisViewNormal[2], preLightData.orthoBasisViewNormal[0]);

{
float3 N = bsdfData.normalWS;
float NdotV = preLightData.clampNdotV;
float LdotV = dot(L, V);
float invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)) - caution about the case where V and L are opposite, it can happen, use max to avoid this
float NdotH = saturate((NdotL + NdotV) * invLenLV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);
float LdotV = dot(L, V);
float invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = NaN
float NdotH = saturate((NdotL + preLightData.NdotV) * invLenLV); // Do not clamp NdotV here
float LdotH = saturate(invLenLV * LdotV + invLenLV);
float NdotV = ClampNdotV(preLightData.NdotV);
float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
float DV;

float3 H = (L + V) * invLenLV;
// For anisotropy we must not saturate these values
float TdotH = dot(bsdfData.tangentWS, H);
float TdotL = dot(bsdfData.tangentWS, L);

[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, preLightData.clampNdotV, attenuation * lightData.diffuseScale);
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, ClampNdotV(preLightData.NdotV), attenuation * lightData.diffuseScale);
}
// Save ALU by applying light and cookie colors only once.

[branch] if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, preLightData.clampNdotV, attenuation * lightData.diffuseScale);
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, ClampNdotV(preLightData.NdotV), attenuation * lightData.diffuseScale);
}
// Save ALU by applying light and cookie colors only once.

#endif
float roughness = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness);
float specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(preLightData.clampNdotV, indirectAmbientOcclusion, roughness);
float specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(ClampNdotV(preLightData.NdotV), indirectAmbientOcclusion, roughness);
// Try to mimic multibounce with specular color. Not the point of the original formula but ok result.
// Take the min of screenspace specular occlusion and visibility cone specular occlusion
#if GTAO_MULTIBOUNCE_APPROX

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitData.hlsl


float alpha = GetSurfaceData(input, layerTexCoord, surfaceData, normalTS, bentNormalTS);
GetNormalWS(input, V, normalTS, surfaceData.normalWS);
// Ensure that the normal is front-facing.
float NdotV;
surfaceData.normalWS = GetViewReflectedNormal(surfaceData.normalWS, V, NdotV);
// Use bent normal to sample GI if available
#ifdef _BENTNORMALMAP
GetNormalWS(input, V, bentNormalTS, bentNormalWS);

// If we have bent normal and ambient occlusion, process a specular occlusion
surfaceData.specularOcclusion = GetSpecularOcclusionFromBentAO(V, bentNormalWS, surfaceData);
#elif defined(_MASKMAP)
surfaceData.specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(NdotV, surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness));
surfaceData.specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(ClampNdotV(dot(surfaceData.normalWS, V)), surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness));
#else
surfaceData.specularOcclusion = 1.0;
#endif

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitDataDisplacement.hlsl


// Since POM "pushes" geometry inwards (rather than extrude it), { height = height - 1 }.
// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign.
float verticalDisplacement = maxHeight - height * maxHeight;
return verticalDisplacement / max(NdotV, 0.001);
return verticalDisplacement / ClampNdotV(NdotV);
#else
return 0.0;
#endif

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitReference.hlsl


uint sampleCount = 4096)
{
float3x3 localToWorld = float3x3(bsdfData.tangentWS, bsdfData.bitangentWS, bsdfData.normalWS);
float NdotV = preLightData.clampNdotV;
float NdotV = ClampNdotV(dot(bsdfData.normalWS, V));
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

localToWorld = GetLocalFrame(bsdfData.normalWS);
}
float NdotV = preLightData.clampNdotV;
float NdotV = ClampNdotV(dot(bsdfData.normalWS, V));
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d

正在加载...
取消
保存