150 lines
6.7 KiB
HLSL
150 lines
6.7 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
struct FLumenCardBasePassOutput
|
|
{
|
|
float4 Target0;
|
|
float4 Target1;
|
|
float4 Target2;
|
|
};
|
|
|
|
FLumenCardBasePassOutput LumenCardBasePass(FPixelMaterialInputs PixelMaterialInputs, FMaterialPixelParameters MaterialParameters, float4 SvPosition)
|
|
{
|
|
#if TEMPLATE_USES_SUBSTRATE
|
|
const float3 V = MaterialParameters.WorldNormal; // Use the normal to avoid view dependent transmittance effects when baking non directional card data.
|
|
const float3 L = MaterialParameters.WorldNormal;
|
|
|
|
float3 DiffuseColor = 0;
|
|
float3 SpecularColor = 0;
|
|
float3 WorldNormal = 0;
|
|
float3 Emissive = 0;
|
|
float TotalCoverage = 1.f;
|
|
|
|
// Initialise a Substrate header with normal in registers
|
|
FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData();
|
|
FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader();
|
|
|
|
#if SUBSTRATE_OPTIMIZED_UNLIT
|
|
|
|
// Unlit BSDF goes through the SubstrateTree to support weighting operations. Technically, layering and mixing could also be supported.
|
|
float3 UnlitSurfaceTransmittancePreCoverage = 0.0f;
|
|
float3 UnlitSurfaceNormal = 0.0f;
|
|
SubstratePixelHeader.SubstrateUpdateTreeUnlit(
|
|
uint2(SvPosition.xy),
|
|
MaterialParameters.CameraVector,
|
|
SubstrateData,
|
|
Emissive,
|
|
TotalCoverage,
|
|
UnlitSurfaceTransmittancePreCoverage,
|
|
UnlitSurfaceNormal);
|
|
|
|
#else // SUBSTRATE_OPTIMIZED_UNLIT
|
|
SubstratePixelHeader.IrradianceAO.MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
|
|
|
|
if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0)
|
|
{
|
|
// To have better 'specular as diffuse' response, we use bForceFullyRoughAccurate which computes specular & diffuse separately.
|
|
// They are both merge them manually at the end, as Lumen card stores only diffuse albedo.
|
|
// Match behavior in LumenHardwareRayTracingCommon.ush
|
|
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(true /*bForceFullyRough*/, true /*bRoughDiffuseEnabled*/, 0 /*PeelLayersAboveDepth*/, false/*bRoughnessTracking*/);
|
|
Settings.bForceFullyRoughAccurate = true;
|
|
|
|
float3 TotalTransmittancePreCoverage = 0;
|
|
SubstratePixelHeader.SubstrateUpdateTree(SubstrateData, V, Settings, TotalCoverage, TotalTransmittancePreCoverage);
|
|
|
|
|
|
// Extract averaged DiffuseAlbedo / SpecularColor
|
|
SUBSTRATE_UNROLL_N(SUBSTRATE_CLAMPED_CLOSURE_COUNT)
|
|
for (int BSDFIdx = 0; BSDFIdx < SubstratePixelHeader.SubstrateTree.BSDFCount; ++BSDFIdx)
|
|
{
|
|
#define CurrentBSDF SubstratePixelHeader.SubstrateTree.BSDFs[BSDFIdx]
|
|
if (SubstrateIsBSDFVisible(CurrentBSDF))
|
|
{
|
|
FSubstrateAddressing NullSubstrateAddressing = (FSubstrateAddressing)0; // Fake unused in SubstrateCreateBSDFContext when using Forward inline shading
|
|
FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, CurrentBSDF, NullSubstrateAddressing, V, L);
|
|
FSubstrateEnvLightResult SubstrateEnvLight = SubstrateEvaluateForEnvLight(SubstrateBSDFContext, true /*bEnableSpecular*/, Settings);
|
|
|
|
// Use LuminanceWeightV instead of LuminanceWeight(..) as we only need to weight these value with the view transmittance, not the light transmittance;
|
|
const float3 Weight = CurrentBSDF.LuminanceWeightV;
|
|
|
|
DiffuseColor += Weight * (SubstrateEnvLight.DiffuseWeight + SubstrateEnvLight.DiffuseBackFaceWeight); // This is not correct, as the albedo/diffuse color can go above 1. However this is necessary to match legacy behavior.
|
|
SpecularColor += Weight * SubstrateEnvLight.SpecularWeight;
|
|
SpecularColor += Weight * SubstrateEnvLight.SpecularHazeWeight;
|
|
WorldNormal += Weight * SubstrateBSDFContext.N;
|
|
Emissive += Weight * CurrentBSDF.Emissive;
|
|
|
|
// Lumen card stores only diffuse albedo, so merge specular & diffuse color,
|
|
// which are propertly weighted respectively to each other
|
|
DiffuseColor = SpecularColor + DiffuseColor;
|
|
|
|
// Note : The legacy path uses a different formulation for composition diffuse and specular color. This result in lighter albedo.
|
|
// If the above formulation causes issues for legacy projects, one could re-enable the code below:
|
|
// DiffuseColor = Weight * SubstrateEnvLight.DiffuseColor;
|
|
// SpecularColor = Weight * SubstrateEnvLight.SpecularColor;
|
|
// EnvBRDFApproxFullyRough(DiffuseColor, SpecularColor);
|
|
}
|
|
#undef CurrentBSDF
|
|
}
|
|
}
|
|
#endif // SUBSTRATE_OPTIMIZED_UNLIT
|
|
|
|
float Opacity = 1.0f;
|
|
#if MATERIALBLENDING_ANY_TRANSLUCENT
|
|
Opacity = TotalCoverage > 0.5f ? 1.0f : 0.0f;
|
|
#elif MATERIALBLENDING_MASKED
|
|
Opacity = GetMaterialMask(PixelMaterialInputs) >= 0.0f ? 1.0f : 0.0f;
|
|
#endif
|
|
|
|
#else // TEMPLATE_USES_SUBSTRATE
|
|
|
|
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
|
|
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
|
|
float Specular = GetMaterialSpecular(PixelMaterialInputs);
|
|
float Roughness = GetMaterialRoughness(PixelMaterialInputs);
|
|
float3 Emissive = GetMaterialEmissive(PixelMaterialInputs);
|
|
float3 WorldNormal = MaterialParameters.WorldNormal;
|
|
|
|
float Opacity = 1.0f;
|
|
#if MATERIALBLENDING_ANY_TRANSLUCENT
|
|
Opacity = GetMaterialOpacity(PixelMaterialInputs) > 0.5f ? 1.0f : 0.0f;
|
|
#elif MATERIALBLENDING_MASKED
|
|
Opacity = GetMaterialMask(PixelMaterialInputs) >= 0.0f ? 1.0f : 0.0f;
|
|
#endif
|
|
|
|
float3 DiffuseColor = BaseColor - BaseColor * Metallic;
|
|
float3 SpecularColor = lerp(0.08f * Specular.xxx, BaseColor, Metallic.xxx);
|
|
|
|
EnvBRDFApproxFullyRough(DiffuseColor, SpecularColor);
|
|
|
|
uint ShadingModel = GetMaterialShadingModel(PixelMaterialInputs);
|
|
|
|
float3 SubsurfaceColor = 0.0f;
|
|
// Match the logic in BasePassPixelShader.usf. MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE and MATERIAL_SHADINGMODEL_EYE
|
|
// are ignored from the following logic as the subsurface color does not contribute to them.
|
|
#if MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_CLOTH
|
|
if (ShadingModel == SHADINGMODELID_SUBSURFACE || ShadingModel == SHADINGMODELID_PREINTEGRATED_SKIN || ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE || ShadingModel == SHADINGMODELID_CLOTH)
|
|
{
|
|
float4 SubsurfaceData = GetMaterialSubsurfaceData(PixelMaterialInputs);
|
|
DiffuseColor += SubsurfaceData.rgb;
|
|
}
|
|
#endif
|
|
|
|
#endif // TEMPLATE_USES_SUBSTRATE
|
|
|
|
// Normals are stored in local card space
|
|
float3 CardSpaceNormal = float3(0, 0, 1);
|
|
|
|
// As of 04/06/2022 sometimes we get NaN normals from Nanite meshes with WPO
|
|
if (all(IsFinite(WorldNormal)))
|
|
{
|
|
WorldNormal = normalize(WorldNormal);
|
|
CardSpaceNormal = mul(float4(WorldNormal, 0.0f), ResolvedView.TranslatedWorldToView).xyz;
|
|
}
|
|
|
|
FLumenCardBasePassOutput ShadedPixel;
|
|
ShadedPixel.Target0 = float4(sqrt(DiffuseColor), Opacity);
|
|
ShadedPixel.Target1 = float4(CardSpaceNormal.xy * 0.5f + 0.5f, 0.0f, /* bValid */ 1.0f);
|
|
ShadedPixel.Target2 = float4(Emissive * LumenCardPass.CachedLightingPreExposure, 0.0f);
|
|
return ShadedPixel;
|
|
} |