浏览代码

Correct based on various feedback

/iridesence
sebastienlagarde 7 年前
当前提交
a40f534c
共有 4 个文件被更改,包括 52 次插入50 次删除
  1. 10
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonMaterial.hlsl
  2. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs
  3. 88
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  4. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/LitData.hlsl

10
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonMaterial.hlsl


}
// Use with stack BRDF (clear coat / coat)
real roughnessToVariance(real roughness)
real RoughnessToVariance(real roughness)
real varianceToRoughness(real variance)
real VarianceToRoughness(real variance)
{
return sqrt(2.0 / (variance + 2.0));
}

// Assume air interface for top
// Note: Don't handle the case fresnel0 == 1
real Fresnel0ToIor(real fresnel0)
real Fresnel0ToIOR(real fresnel0)
{
real sqrtF0 = sqrt(fresnel0);
return (1.0 + sqrtF0) / (1.0 - sqrtF0);

// This function is equivalent to IORToFresnel0(Fresnel0ToIor(fresnel0), 1.5)
// This function is equivalent to IORToFresnel0(Fresnel0ToIOR(fresnel0), 1.5)
TEMPLATE_1_REAL(Fresnel0ReajustFor15, fresnel0, return saturate(-0.0256868 + fresnel0 * (0.326846 + (0.978946 - 0.283835 * fresnel0) * fresnel0)) )
TEMPLATE_1_REAL(ConvertF0ForAirInterfaceToF0ForClearCoat15, fresnel0, return saturate(-0.0256868 + fresnel0 * (0.326846 + (0.978946 - 0.283835 * fresnel0) * fresnel0)) )
// same as regular refract except there is not the test for total internal reflection + the vector is flipped for processing
real3 CoatRefract(real3 X, real3 N, real ieta)

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs


public static GUIContent thicknessRemapText = new GUIContent("Thickness Remap", "Remaps values of the thickness map from [0, 1] to the specified range.");
// Clear Coat
public static GUIContent coatMaskText = new GUIContent("Coat Mask", "attenuate the coating effect (similar to change to IOR of 1");
public static GUIContent coatMaskText = new GUIContent("Coat Mask", "Attenuate the coating effect (similar to change to IOR of 1");
// Specular color
public static GUIContent specularColorText = new GUIContent("Specular Color", "Specular color (RGB)");

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


#define GBUFFER_LIT_ANISOTROPIC_UPPER_BOUND 12
#define CLEAR_COAT_IOR 1.5
#define CLEAR_COAT_IETA (1.0 / CLEAR_COAT_IOR)
#define CLEAR_COAT_IETA (1.0 / CLEAR_COAT_IOR) // IETA is the inverse eta which is the ratio of IOR of two interface
#define CLEAR_COAT_PERCEPTUAL_ROUGHNESS 0.031622
#define CLEAR_COAT_ROUGHNESS (CLEAR_COAT_PERCEPTUAL_ROUGHNESS * CLEAR_COAT_PERCEPTUAL_ROUGHNESS) // 0.001
#define CLEAR_COAT_ROUGHNESS 0.001
#define CLEAR_COAT_PERCEPTUAL_ROUGHNESS RoughnessToPerceptualRoughness(CLEAR_COAT_ROUGHNESS)
//-----------------------------------------------------------------------------
// Configuration

// Approx to deal with roughness appearance of base layer (should appear rougher)
float coatRoughnessScale = Sq(ieta);
float sigma = roughnessToVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness));
bsdfData.perceptualRoughness = RoughnessToPerceptualRoughness(varianceToRoughness(sigma * coatRoughnessScale));
// fresnel0 is deduced from interface between air and material (assume to be 1.5 in Unity, or a metal).
float sigma = RoughnessToVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness));
bsdfData.perceptualRoughness = RoughnessToPerceptualRoughness(VarianceToRoughness(sigma * coatRoughnessScale));
// Fresnel0 is deduced from interface between air and material (Assume to be 1.5 in Unity, or a metal).
bsdfData.fresnel0 = Fresnel0ReajustFor15(bsdfData.fresnel0);
bsdfData.fresnel0 = ConvertF0ForAirInterfaceToF0ForClearCoat15(bsdfData.fresnel0);
}
void FillMaterialTransparencyData(float3 baseColor, float metallic, float ior, float3 transmittanceColor, float atDistance, float thickness, float transmittanceMask, inout BSDFData bsdfData)

bsdfData.enableSpecularColor = surfaceData.enableSpecularColor;
bsdfData.enableSubsurfaceScattering = surfaceData.enableSubsurfaceScattering;
bsdfData.enableTransmission = surfaceData.enableTransmission;
bsdfData.enableAnisotropy = surfaceData.enableAnisotropy;
bsdfData.enableAnisotropy = surfaceData.enableAnisotropy;
bsdfData.enableIridescence = surfaceData.enableIridescence;
bsdfData.enableClearCoat = surfaceData.enableClearCoat;

float ltcMagnitudeCoatFresnel;
// Refraction
float3 transmissionRefractV; // refracted view vector after exiting the shape
float3 transmissionPositionWS; // start of the refracted ray after exiting the shape
float3 transmissionTransmittance; // transmittance due to absorption
float transmissionSSMipLevel; // 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 transparentSMipLevel; // mip level of the screen space gaussian pyramid for rough refraction
};
PreLightData GetPreLightData(float3 V, PositionInputs posInput, BSDFData bsdfData)

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.iblPerceptualRoughness = bsdfData.perceptualRoughness;
// Clear coat need to modify roughness, V and NdotV for all the other precalculation below
if (bsdfData.enableClearCoat)
{
preLightData.coatPartLambdaV = GetSmithJointGGXPartLambdaV(NdotV, CLEAR_COAT_ROUGHNESS);

preLightData.ltcTransformCoat._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
ltcGGXFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcMagnitudeCoatFresnel = (CLEAR_COAT_F0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude) * bsdfData.coatMask;
ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
ltcGGXFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcMagnitudeCoatFresnel = (CLEAR_COAT_F0 * ltcGGXFresnelMagnitudeDiff + ltcGGXFresnelMagnitude) * bsdfData.coatMask;
preLightData.transmissionRefractV = refraction.rayWS;
preLightData.transmissionPositionWS = refraction.positionWS;
preLightData.transmissionTransmittance = exp(-bsdfData.absorptionCoefficient * refraction.dist);
preLightData.transparentRefractV = refraction.rayWS;
preLightData.transparentPositionWS = refraction.positionWS;
preLightData.transparentTransmittance = exp(-bsdfData.absorptionCoefficient * refraction.dist);
preLightData.transmissionSSMipLevel = sqrt(preLightData.iblPerceptualRoughness) * uint(_GaussianPyramidColorMipSize.z);
preLightData.transparentSMipLevel = sqrt(preLightData.iblPerceptualRoughness) * uint(_GaussianPyramidColorMipSize.z);
#endif
return preLightData;

// BSDF share between directional light, punctual light and area light (reference)
//-----------------------------------------------------------------------------
// This function apply BSDF * cos (required to deal with clear coating)
// This function apply BSDF
void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BSDFData bsdfData,
out float3 diffuseLighting,
out float3 specularLighting)

// Note: The modification of the base roughness and fresnel0 by the clear coat is already handled in FillMaterialClearCoatData
// Scale diffuse for energy conservation (use NdotL as an approximation)
// Very coarse attempt at doing energy conservation for the diffuse layer based on NdotL. No science.
diffuseLighting *= F_Schlick(CLEAR_COAT_F0, NdotL);
}
}

// Simulate a sphere light with this hack
// Note that it is not correct with our pre-computation of PartLambdaV (mean if we disable the optimization we will not have the
// same result) but we don't care as it is a hack anyway
if (bsdfData.enableClearCoat)
{
bsdfData.coatRoughness = max(bsdfData.coatRoughness, lightData.minRoughness);
}
bsdfData.coatRoughness = max(bsdfData.coatRoughness, lightData.minRoughness);
bsdfData.roughnessT = max(bsdfData.roughnessT, lightData.minRoughness);
bsdfData.roughnessB = max(bsdfData.roughnessB, lightData.minRoughness);

// Evaluate the diffuse part
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformDiffuse);
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;

// The matrix multiplication should not generate any extra ALU on GCN.
// TODO: double evaluation is very inefficient! This is a temporary solution.
ltcValue = LTCEvaluate(P1, P2, B, mul(flipMatrix, k_identity3x3));
ltcValue *= lightData.diffuseScale;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += bsdfData.transmittance * ltcValue;

ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformSpecular);
ltcValue *= lightData.specularScale;
lighting.specular = preLightData.ltcMagnitudeFresnel * ltcValue;
// Evaluate the coat part

lighting.specular *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformCoat);
ltcValue *= lightData.specularScale;
lighting.diffuse *= lightData.color * lightData.diffuseScale;
lighting.specular *= lightData.color * lightData.specularScale;;
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
return lighting;

// Evaluate the diffuse part
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformDiffuse));
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;

// Polygon irradiance in the transformed configuration.
// TODO: double evaluation is very inefficient! This is a temporary solution.
ltcValue = PolygonIrradiance(mul(lightVerts, ltcTransform));
ltcValue *= lightData.diffuseScale;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += bsdfData.transmittance * ltcValue;

// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformSpecular));
ltcValue *= lightData.specularScale;
lighting.specular += preLightData.ltcMagnitudeFresnel * ltcValue;
// Evaluate the coat part

lighting.specular *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformCoat));
ltcValue *= lightData.specularScale;
lighting.diffuse *= lightData.color * lightData.diffuseScale;
lighting.specular *= lightData.color * lightData.specularScale;
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
return lighting;

// a. Get the corresponding color depending on the roughness from the gaussian pyramid of the color buffer
// b. Multiply by the transmittance for absorption (depends on the optical depth)
float3 refractedBackPointWS = EstimateRaycast(V, posInput, preLightData.transmissionPositionWS, preLightData.transmissionRefractV);
float3 refractedBackPointWS = EstimateRaycast(V, posInput, preLightData.transparentPositionWS, preLightData.transparentRefractV);
// Calculate screen space coordinates of refracted point in back plane
float2 refractedBackPointNDC = ComputeNormalizedDeviceCoordinates(refractedBackPointWS, UNITY_MATRIX_VP);

}
// Map the roughness to the correct mip map level of the color pyramid
lighting.specularTransmitted = SAMPLE_TEXTURE2D_LOD(_GaussianPyramidColorTexture, s_trilinear_clamp_sampler, refractedBackPointNDC, preLightData.transmissionSSMipLevel).rgb;
lighting.specularTransmitted = SAMPLE_TEXTURE2D_LOD(_GaussianPyramidColorTexture, s_trilinear_clamp_sampler, refractedBackPointNDC, preLightData.transparentSMipLevel).rgb;
lighting.specularTransmitted *= preLightData.transmissionTransmittance;
lighting.specularTransmitted *= preLightData.transparentTransmittance;
float weight = 1.0;
UpdateLightingHierarchyWeights(hierarchyWeight, weight); // Shouldn't be needed, but safer in case we decide to change hierarchy priority

if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION)
{
positionWS = preLightData.transmissionPositionWS;
R = preLightData.transmissionRefractV;
positionWS = preLightData.transparentPositionWS;
R = preLightData.transparentRefractV;
}
// In Unity the cubemaps are capture with the localToWorld transform of the component.

R = (positionWS + projectionDistance * R) - lightData.positionWS;
// Test again for clear code
if (bsdfData.enableClearCoat)
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION && bsdfData.enableClearCoat)
{
dirLS = mul(coatR, worldToLocal);
projectionDistance = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);

// TODO: add distance based roughness
// Test again for clear code
if (bsdfData.enableClearCoat)
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION && bsdfData.enableClearCoat)
{
dirLS = mul(coatR, worldToLocal);
projectionDistance = BoxRayIntersectSimple(positionLS, dirLS, -boxOuterDistance, boxOuterDistance);

}
else
{
// No clear coat support with refraction
envLighting = (1.0 - F) * preLD.rgb * preLightData.transmissionTransmittance;
// Don't account for clear coat to save ALU
envLighting = (1.0 - F) * preLD.rgb * preLightData.transparentTransmittance;
}
#endif // LIT_DISPLAY_REFERENCE_IBL

if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION)
lighting.specularReflected = envLighting;
else
lighting.specularTransmitted = envLighting * preLightData.transmissionTransmittance;
lighting.specularTransmitted = envLighting * preLightData.transparentTransmittance;
return lighting;
}

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


// however it will not optimize the lightprobe case due to the proxy volume relying on dynamic if (we rely must get right of this dynamic if), not a problem for SH9, but a problem for proxy volume.
// TODO: optimize more this code.
// Add GI transmission contribution by resampling the GI for inverted vertex normal
builtinData.bakeDiffuseLighting += SampleBakedGI(input.positionWS, -input.worldToTangent[2], input.texCoord1, input.texCoord2) * bsdfData.transmittance;
builtinData.bakeDiffuseLighting += SampleBakedGI(input.positionWS, -input.worldToTangent[2], input.texCoord1, input.texCoord2) * bsdfData.transmittance * _TransmittanceMultiplier;
}
#ifdef SHADOWS_SHADOWMASK

正在加载...
取消
保存