1015 lines
38 KiB
HLSL
1015 lines
38 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#define ENABLE_SKY_LIGHT 1
|
|
#define NEEDS_LIGHTMAP_COORDINATE (HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP)
|
|
#ifdef NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
#undef NEEDS_VERTEX_FACTORY_INTERPOLATION
|
|
#endif
|
|
// Needed for VertexFactoryInterpolate to interpolate attributes from vertices to hit point
|
|
#define NEEDS_VERTEX_FACTORY_INTERPOLATION 1
|
|
|
|
// This should be good enough for ray tracing and avoids having to bind an extra buffer
|
|
#define EYE_ADAPTATION_PREV_FRAME_EXPOSURE 1
|
|
|
|
#if SUBSTRATE_ENABLED
|
|
#define SUBSTRATE_INLINE_SHADING 1
|
|
#define SUBSTRATE_USES_FORCED_COMPLEXITY 0
|
|
#endif
|
|
|
|
// Force simplified RT shader to not use complex special path
|
|
#if SUBSTRATE_USE_FULLYSIMPLIFIED_MATERIAL
|
|
#ifdef SUBSTRATE_COMPLEXSPECIALPATH
|
|
#undef SUBSTRATE_COMPLEXSPECIALPATH
|
|
#endif
|
|
#define SUBSTRATE_COMPLEXSPECIALPATH 0
|
|
#endif
|
|
|
|
#include "/Engine/Private/Common.ush"
|
|
#include "RayTracingCommon.ush"
|
|
#include "RayTracingHitGroupCommon.ush"
|
|
#include "RayTracingShaderUtils.ush"
|
|
#include "/Engine/Private/PathTracing/Material/PathTracingFresnel.ush"
|
|
|
|
#include "/Engine/Generated/Material.ush"
|
|
#include "/Engine/Generated/VertexFactory.ush"
|
|
|
|
#include "RayTracingCalcInterpolants.ush" // must be included after VertexFactory.ush
|
|
#include "/Engine/Private/ShadingCommon.ush"
|
|
#include "/Engine/Private/DeferredShadingCommon.ush"
|
|
#include "/Engine/Private/SHCommon.ush"
|
|
#include "/Engine/Private/ReflectionEnvironmentShared.ush"
|
|
#include "/Engine/Private/VirtualTextureCommon.ush"
|
|
#include "/Engine/Private/LightmapCommon.ush"
|
|
#include "/Engine/Private/Lumen/LumenHardwareRayTracingPayloadCommon.ush"
|
|
|
|
#define MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING 0
|
|
#include "/Engine/Private/Substrate/SubstrateExport.ush"
|
|
|
|
/** Computes sky diffuse lighting, including precomputed shadowing. */
|
|
void GetSkyLighting(
|
|
FMaterialPixelParameters MaterialParameters,
|
|
VTPageTableResult LightmapVTPageTableResult,
|
|
float3 WorldNormal,
|
|
LightmapUVType LightmapUV,
|
|
uint LightmapDataIndex,
|
|
float3 SkyOcclusionUV3D,
|
|
uint ShadingModel,
|
|
bool bEnableSkyLightContribution,
|
|
out float3 OutDiffuseLighting,
|
|
out float3 OutSubsurfaceLighting)
|
|
{
|
|
OutDiffuseLighting = float3(0,0,0);
|
|
OutSubsurfaceLighting = float3(0,0,0);
|
|
|
|
// TODO:
|
|
// Should apply Lumen Dynamic GI + shadowed Skylight based on IsLumenTranslucencyGIEnabled() here
|
|
// however we are not binding the unnecessary shader parameters in hitgroups at the moment
|
|
|
|
#if ENABLE_SKY_LIGHT
|
|
|
|
// Check if the Sky Light contribution should be ignored
|
|
if (!bEnableSkyLightContribution)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float SkyVisibility = 1;
|
|
float GeometryTerm = 1;
|
|
float3 SkyLightingNormal = WorldNormal;
|
|
|
|
#if HQ_TEXTURE_LIGHTMAP || CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING || PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
BRANCH
|
|
if (ShouldSkyLightApplyPrecomputedBentNormalShadowing())
|
|
{
|
|
#if PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
|
|
float3 SkyBentNormal = GetVolumetricLightmapSkyBentNormal(SkyOcclusionUV3D);
|
|
SkyVisibility = length(SkyBentNormal);
|
|
float3 NormalizedBentNormal = SkyBentNormal / max(SkyVisibility, .0001f);
|
|
|
|
#elif HQ_TEXTURE_LIGHTMAP
|
|
|
|
// Bent normal from precomputed texture
|
|
float4 WorldSkyBentNormalAndOcclusion = GetSkyBentNormalAndOcclusion(LightmapVTPageTableResult, ScaleLightmapUV(LightmapUV, float2(1.0f, 2.0f)), LightmapDataIndex, MaterialParameters.SvPosition.xy);
|
|
// Renormalize as vector was quantized and compressed
|
|
float3 NormalizedBentNormal = normalize(WorldSkyBentNormalAndOcclusion.xyz);
|
|
SkyVisibility = WorldSkyBentNormalAndOcclusion.w;
|
|
|
|
#elif CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
|
|
|
|
// Bent normal from the indirect lighting cache - one value for the whole object
|
|
float3 NormalizedBentNormal = IndirectLightingCache.PointSkyBentNormal.xyz;
|
|
SkyVisibility = IndirectLightingCache.PointSkyBentNormal.w;
|
|
|
|
#endif
|
|
|
|
#if (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE) && (TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL)
|
|
// NonDirectional lighting can't depend on the normal
|
|
SkyLightingNormal = NormalizedBentNormal;
|
|
#else
|
|
|
|
// Weight toward the material normal to increase directionality
|
|
float BentNormalWeightFactor = 1 - (1 - SkyVisibility) * (1 - SkyVisibility);
|
|
|
|
// We are lerping between the inputs of two lighting scenarios based on occlusion
|
|
// In the mostly unoccluded case, evaluate sky lighting with the material normal, because it has higher detail
|
|
// In the mostly occluded case, evaluate sky lighting with the bent normal, because it is a better representation of the incoming lighting
|
|
// Then treat the lighting evaluated along the bent normal as an area light, so we must apply the lambert term
|
|
SkyLightingNormal = lerp(NormalizedBentNormal, WorldNormal, BentNormalWeightFactor);
|
|
|
|
float DotProductFactor = lerp(saturate(dot(NormalizedBentNormal, WorldNormal)), 1, BentNormalWeightFactor);
|
|
// Account for darkening due to the geometry term
|
|
GeometryTerm = DotProductFactor;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// Compute the preconvolved incoming lighting with the bent normal direction
|
|
float3 DiffuseLookup = GetSkySHDiffuse(SkyLightingNormal) * ResolvedView.SkyLightColor.rgb;
|
|
|
|
// Apply AO to the sky diffuse
|
|
OutDiffuseLighting += DiffuseLookup * (SkyVisibility * GeometryTerm);
|
|
|
|
#if MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
|
|
if (ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE)
|
|
{
|
|
float3 BackfaceDiffuseLookup = GetSkySHDiffuse(-WorldNormal) * ResolvedView.SkyLightColor.rgb;
|
|
OutSubsurfaceLighting += BackfaceDiffuseLookup * SkyVisibility;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
#if !SUBSTRATE_ENABLED || SUBTRATE_GBUFFER_FORMAT==0
|
|
// TODO: Consolidate this definition with similar one in PathTracing Material
|
|
float GetRefractionIor(FPixelMaterialInputs PixelMaterialInputs)
|
|
{
|
|
#if MATERIALBLENDING_TRANSLUCENT && REFRACTION_USE_INDEX_OF_REFRACTION
|
|
// Is the material using refraction at all?
|
|
#if REFRACTION_ROOT_NODE_OVERRIDES_DEFAULT
|
|
// Did the user plug something into the Refraction port?
|
|
// Return the user's IOR value, or 0 (ensure we don't get anything negative)
|
|
return max(GetMaterialRefractionIOR(GetMaterialRefraction(PixelMaterialInputs)), 0.0);
|
|
#else
|
|
// User did not override the default, compute it via the amount of specular
|
|
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
|
|
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
|
|
float Specular = GetMaterialSpecular(PixelMaterialInputs);
|
|
float3 F0 = ComputeF0(Specular, BaseColor, Metallic);
|
|
return DielectricF0RGBToIor(F0);
|
|
#endif
|
|
|
|
#else
|
|
// Material either not translucent, or does use have IOR refraction enabled
|
|
return 0.0;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** Calculates indirect lighting contribution on this object from precomputed data. */
|
|
void GetPrecomputedIndirectLightingAndSkyLight(
|
|
FMaterialPixelParameters MaterialParameters,
|
|
FVertexFactoryInterpolantsVSToPS Interpolants,
|
|
VTPageTableResult LightmapVTPageTableResult,
|
|
float3 DiffuseDir,
|
|
float3 VolumetricLightmapBrickTextureUVs,
|
|
bool bEvaluateBackface,
|
|
bool bEnableSkyLightContribution,
|
|
out float3 OutDiffuseLighting,
|
|
out float3 OutSubsurfaceLighting,
|
|
out float OutIndirectIrradiance)
|
|
{
|
|
OutIndirectIrradiance = 0;
|
|
OutDiffuseLighting = float3(0,0,0);
|
|
OutSubsurfaceLighting = 0;
|
|
LightmapUVType SkyOcclusionUV = (LightmapUVType)0;
|
|
uint SkyOcclusionDataIndex = 0u;
|
|
|
|
#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
|
|
LightmapUVType LightmapUV0, LightmapUV1;
|
|
uint LightmapDataIndex;
|
|
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
|
|
#if LIGHTMAP_VT_ENABLED
|
|
LightmapVTPageTableResult = LightmapGetVTSampleInfo(LightmapUV0, LightmapDataIndex, MaterialParameters.SvPosition.xy);
|
|
#endif
|
|
#endif
|
|
|
|
#if PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
FThreeBandSHVectorRGB IrradianceSH = GetVolumetricLightmapSH3(VolumetricLightmapBrickTextureUVs);
|
|
|
|
// Diffuse convolution
|
|
FThreeBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH3(DiffuseDir, 1);
|
|
OutDiffuseLighting = max(float3(0,0,0), DotSH3(IrradianceSH, DiffuseTransferSH)) / PI;
|
|
|
|
#if MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
|
|
if (bEvaluateBackface)
|
|
{
|
|
FThreeBandSHVector SubsurfaceTransferSH = CalcDiffuseTransferSH3(-DiffuseDir, 1);
|
|
OutSubsurfaceLighting += max(float3(0,0,0), DotSH3(IrradianceSH, SubsurfaceTransferSH)) / PI;
|
|
}
|
|
#endif
|
|
|
|
// High quality texture lightmaps
|
|
#elif HQ_TEXTURE_LIGHTMAP
|
|
|
|
SkyOcclusionUV = LightmapUV0;
|
|
SkyOcclusionDataIndex = LightmapDataIndex;
|
|
GetLightMapColorHQ(LightmapVTPageTableResult, LightmapUV0, LightmapUV1, LightmapDataIndex, DiffuseDir, MaterialParameters.SvPosition.xy, bEvaluateBackface, OutDiffuseLighting, OutSubsurfaceLighting);
|
|
|
|
// Low quality texture lightmaps
|
|
#elif LQ_TEXTURE_LIGHTMAP
|
|
|
|
GetLightMapColorLQ(LightmapVTPageTableResult, LightmapUV0, LightmapUV1, LightmapDataIndex, DiffuseDir, bEvaluateBackface, OutDiffuseLighting, OutSubsurfaceLighting);
|
|
|
|
#endif
|
|
|
|
// Apply indirect lighting scale while we have only accumulated lightmaps
|
|
OutDiffuseLighting *= View.PrecomputedIndirectLightingColorScale;
|
|
OutSubsurfaceLighting *= View.PrecomputedIndirectLightingColorScale;
|
|
|
|
float3 SkyDiffuseLighting;
|
|
float3 SkySubsurfaceLighting;
|
|
GetSkyLighting(
|
|
MaterialParameters,
|
|
LightmapVTPageTableResult,
|
|
DiffuseDir,
|
|
SkyOcclusionUV,
|
|
SkyOcclusionDataIndex,
|
|
VolumetricLightmapBrickTextureUVs,
|
|
bEvaluateBackface,
|
|
bEnableSkyLightContribution,
|
|
SkyDiffuseLighting,
|
|
SkySubsurfaceLighting);
|
|
|
|
OutSubsurfaceLighting += SkySubsurfaceLighting;
|
|
|
|
// Sky lighting must contribute to IndirectIrradiance for ReflectionEnvironment lightmap mixing
|
|
OutDiffuseLighting += SkyDiffuseLighting;
|
|
|
|
#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP || CACHED_VOLUME_INDIRECT_LIGHTING || CACHED_POINT_INDIRECT_LIGHTING || PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
OutIndirectIrradiance = Luminance(OutDiffuseLighting);
|
|
#endif
|
|
}
|
|
|
|
void GetMaterialPayload(
|
|
FPixelMaterialInputs PixelMaterialInputs,
|
|
FMaterialPixelParameters MaterialParameters,
|
|
FVertexFactoryInterpolantsVSToPS Interpolants,
|
|
bool bIsEnableSkyLightContribution,
|
|
float Dither,
|
|
inout FMaterialClosestHitPayload Payload)
|
|
#if SUBTRATE_GBUFFER_FORMAT==1
|
|
{
|
|
#if MATERIAL_IS_SUBSTRATE
|
|
float3 EmissiveLuminance = 0.0f;
|
|
float TotalCoverage = 1.f;
|
|
float3 TransmittancePreCoverage = 0.0f;
|
|
bool bSubstrateSubsurfaceEnable = false;
|
|
const float3 WorldBentNormal0 = GetWorldBentNormalZero(MaterialParameters);
|
|
const float3 CamVector = MaterialParameters.CameraVector;
|
|
|
|
// 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 UnlitSurfaceLuminancePostCoverage = 0.0f;
|
|
float UnlitSurfaceCoverage = 0.0f;
|
|
float3 UnlitSurfaceTransmittancePreCoverage = 0.0f;
|
|
float3 UnlitSurfaceNormal = 0.0f;
|
|
SubstratePixelHeader.SubstrateUpdateTreeUnlit(
|
|
uint2(MaterialParameters.SvPosition.xy),
|
|
CamVector,
|
|
SubstrateData,
|
|
UnlitSurfaceLuminancePostCoverage,
|
|
UnlitSurfaceCoverage,
|
|
UnlitSurfaceTransmittancePreCoverage,
|
|
UnlitSurfaceNormal);
|
|
EmissiveLuminance = UnlitSurfaceLuminancePostCoverage;
|
|
|
|
#if !SUBSTRATE_OPAQUE_MATERIAL
|
|
TotalCoverage = UnlitSurfaceCoverage;
|
|
TransmittancePreCoverage = UnlitSurfaceTransmittancePreCoverage;
|
|
#endif
|
|
|
|
#else // SUBSTRATE_OPTIMIZED_UNLIT
|
|
SubstratePixelHeader.IrradianceAO.MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
|
|
SubstratePixelHeader.SetCastContactShadow(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAST_CONTACT_SHADOW);
|
|
SubstratePixelHeader.SetDynamicIndirectShadowCasterRepresentation(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAPSULE_REPRESENTATION);
|
|
|
|
FSubstrateSubsurfaceData SSSData = (FSubstrateSubsurfaceData)0;
|
|
FSubstrateTopLayerData TopLayerData = (FSubstrateTopLayerData)0;
|
|
FSubstrateOpaqueRoughRefractionData OpaqueRoughRefractionData = (FSubstrateOpaqueRoughRefractionData)0;
|
|
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings();
|
|
|
|
// Generate the Substrate material data to write out
|
|
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(0,0,0);
|
|
|
|
// Compute TotalCoverage for translucent material
|
|
#if MATERIALBLENDING_ANY_TRANSLUCENT
|
|
if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0)
|
|
{
|
|
SubstratePixelHeader.SubstrateUpdateTree(
|
|
SubstrateData,
|
|
CamVector,
|
|
Settings,
|
|
TotalCoverage,
|
|
TransmittancePreCoverage);
|
|
|
|
}
|
|
#endif
|
|
|
|
Payload.SubstrateData = InitialiseRWSubstrateMaterialContainer();
|
|
PackSubstrateOut(
|
|
Payload.SubstrateData,
|
|
Dither,
|
|
Settings,
|
|
SubstrateAddressing,
|
|
SubstratePixelHeader, SubstrateData,
|
|
CamVector,
|
|
WorldBentNormal0,
|
|
bSubstrateSubsurfaceEnable,
|
|
EmissiveLuminance,
|
|
SSSData, TopLayerData, OpaqueRoughRefractionData
|
|
);
|
|
|
|
// Sky lighting and lightmap
|
|
Payload.IndirectIrradiance = 0;
|
|
if (bIsEnableSkyLightContribution)
|
|
{
|
|
#define CurrentBSDF SubstratePixelHeader.SubstrateTree.BSDFs[0]
|
|
|
|
float3 VolumetricLightmapBrickTextureUVs;
|
|
#if PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
VolumetricLightmapBrickTextureUVs = ComputeVolumetricLightmapBrickTextureUVs(WSHackToFloat(GetWorldPosition(MaterialParameters))); // RT_LWC_TODO
|
|
#endif
|
|
|
|
VTPageTableResult LightmapVTPageTableResult = (VTPageTableResult)0.0f;
|
|
|
|
FSubstrateAddressing NullSubstrateAddressing = (FSubstrateAddressing)0;
|
|
FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, CurrentBSDF, NullSubstrateAddressing, CamVector);
|
|
|
|
// Fetch precomputed lighting
|
|
float3 DiffuseLighting = 0.0f;
|
|
float3 SubsurfaceLighting = 0.0f;
|
|
float IndirectIrradiance = 0.0f;
|
|
const bool bEvaluateBackface = BSDF_GETTYPE(CurrentBSDF) == SUBSTRATE_BSDF_TYPE_SLAB && BSDF_GETSSSTYPE(CurrentBSDF) == SSS_TYPE_TWO_SIDED_WRAP;
|
|
|
|
GetPrecomputedIndirectLightingAndSkyLight(
|
|
MaterialParameters,
|
|
Interpolants,
|
|
LightmapVTPageTableResult,
|
|
SubstrateBSDFContext.N,
|
|
VolumetricLightmapBrickTextureUVs,
|
|
bEvaluateBackface,
|
|
bIsEnableSkyLightContribution,
|
|
DiffuseLighting,
|
|
SubsurfaceLighting,
|
|
IndirectIrradiance);
|
|
|
|
Payload.IndirectIrradiance = DiffuseLighting;
|
|
Payload.SetHasIndirectLighting();
|
|
|
|
#undef CurrentBSDF
|
|
}
|
|
|
|
Payload.SubstrateData.PackedTopLayerData = SubstratePackTopLayerData(TopLayerData);
|
|
#endif // SUBSTRATE_OPTIMIZED_UNLIT
|
|
|
|
Payload.Radiance += EmissiveLuminance;
|
|
Payload.TranslatedWorldPos = DFFastToTranslatedWorld(MaterialParameters.AbsoluteWorldPosition, ResolvedView.PreViewTranslation);
|
|
|
|
#if MATERIALBLENDING_ANY_TRANSLUCENT && REFRACTION_USE_INDEX_OF_REFRACTION
|
|
#if REFRACTION_ROOT_NODE_OVERRIDES_DEFAULT
|
|
Payload.IorOverride = max(GetMaterialRefractionIOR(GetMaterialRefraction(PixelMaterialInputs)), 0);
|
|
#else
|
|
// IOR will be derived from specular color
|
|
Payload.IorOverride = -1.0f;
|
|
#endif
|
|
#else
|
|
Payload.IorOverride = 0;
|
|
#endif
|
|
|
|
// Opacity
|
|
#if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE // AlphaComposite - Premultiplied alpha blending
|
|
TotalCoverage = 1.0f;
|
|
TransmittancePreCoverage = 1.0f - GetMaterialOpacity(PixelMaterialInputs);
|
|
#endif
|
|
Payload.Opacity = TotalCoverage;
|
|
Payload.TransmittancePreCoverage = TransmittancePreCoverage;
|
|
|
|
#if MATERIALBLENDING_MASKED
|
|
// regular masked mode - binary decision
|
|
if (GetMaterialMask(PixelMaterialInputs) < 0)
|
|
{
|
|
Payload.Opacity = 0;
|
|
}
|
|
#endif // MATERIALBLENDING_MASKED
|
|
|
|
|
|
#endif // MATERIAL_IS_SUBSTRATE
|
|
}
|
|
#else // SUBTRATE_GBUFFER_FORMAT==1
|
|
{
|
|
|
|
#if !SUBSTRATE_ENABLED
|
|
// Store the results in local variables and reuse instead of calling the functions multiple times.
|
|
half3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
|
|
half Metallic = GetMaterialMetallic(PixelMaterialInputs);
|
|
half Specular = GetMaterialSpecular(PixelMaterialInputs);
|
|
half Roughness = GetMaterialRoughness(PixelMaterialInputs);
|
|
half IOR = GetRefractionIor(PixelMaterialInputs);
|
|
half3 EmissiveColor = GetMaterialEmissive(PixelMaterialInputs);
|
|
half3 WorldNormal = normalize(MaterialParameters.WorldNormal);
|
|
half Opacity = GetMaterialOpacity(PixelMaterialInputs);
|
|
half4 CustomData = half4(GetMaterialCustomData0(PixelMaterialInputs), GetMaterialCustomData1(PixelMaterialInputs), 0, 0);
|
|
half4 SubsurfaceData = GetMaterialSubsurfaceData(PixelMaterialInputs);
|
|
half4 ClothData = float4(SubsurfaceData.rgb, CustomData.x);
|
|
|
|
half3 WorldTangent = 0.0f;
|
|
half Anisotropy = 0.0f;
|
|
#if MATERIAL_USES_ANISOTROPY
|
|
WorldTangent = CalculateAnisotropyTangent(MaterialParameters, PixelMaterialInputs);
|
|
Anisotropy = GetMaterialAnisotropy(PixelMaterialInputs);
|
|
#endif
|
|
#else
|
|
// Here are in the case SUBSTRATE_ENABLED && SUBTRATE_GBUFFER_FORMAT==0
|
|
|
|
FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData();
|
|
FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader();
|
|
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings();
|
|
|
|
const float3 SurfaceWorldNormal = MaterialParameters.TangentToWorld[2].xyz;
|
|
FExportResult Export = SubstrateMaterialExportOut(
|
|
Settings,
|
|
SubstratePixelHeader,
|
|
SubstrateData,
|
|
SurfaceWorldNormal,
|
|
MaterialParameters.WorldPosition_CamRelative,
|
|
0.0f // Curvature
|
|
);
|
|
|
|
half3 BaseColor = Export.BaseColor;
|
|
half Metallic = Export.Metallic;
|
|
half Specular = Export.Specular;
|
|
half Roughness = Export.Roughness;
|
|
half IOR = GetRefractionIor(PixelMaterialInputs); // SUBSTRATE_TODO Task add in order to converrt that function to be Substrate compatible.
|
|
half3 EmissiveColor = Export.EmissiveLuminance;
|
|
half3 WorldNormal = Export.WorldNormal;
|
|
half Opacity = Export.Coverage;
|
|
half4 CustomData = Export.CustomData;
|
|
half4 ClothData = Export.CustomData;
|
|
half4 SubsurfaceData = half4(Export.SubsurfaceColor, 0.0);
|
|
|
|
half3 WorldTangent = 0.0f;
|
|
half Anisotropy = 0.0f;
|
|
#if MATERIAL_USES_ANISOTROPY
|
|
WorldTangent = Export.WorldTangent;
|
|
Anisotropy = Export.Anisotropy;
|
|
#endif
|
|
|
|
Payload.ShadingModelID = Export.ShadingModelID; // Override the shading model using the one from Substrate
|
|
#endif
|
|
|
|
/**
|
|
* Set material attributes for full materials
|
|
**/
|
|
Payload.TranslatedWorldPos = DFFastToTranslatedWorld(MaterialParameters.AbsoluteWorldPosition, ResolvedView.PreViewTranslation);
|
|
Payload.WorldNormal = WorldNormal;
|
|
Payload.Radiance = EmissiveColor;
|
|
Payload.BaseColor = BaseColor;
|
|
Payload.Specular = Specular;
|
|
Payload.Roughness = Roughness;
|
|
Payload.Metallic = Metallic;
|
|
#if MATERIALBLENDING_MODULATE
|
|
Payload.Opacity = 0.0;
|
|
#else
|
|
// All other blending modes
|
|
Payload.Opacity = Opacity;
|
|
#endif
|
|
|
|
Payload.Ior = IOR;
|
|
Payload.CustomData = CustomData;
|
|
|
|
#if !SUBSTRATE_ENABLED // Not need to do that since the SubstrateExport already handle the CustomData all at once.
|
|
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
|
|
#if CLEAR_COAT_BOTTOM_NORMAL
|
|
if (Payload.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
|
|
{
|
|
float2 oct2 = UnitVectorToOctahedron(Payload.WorldNormal);
|
|
|
|
#if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
|
|
#if MATERIAL_TANGENTSPACENORMAL
|
|
float3 tempnormal = normalize(TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, ClearCoatBottomNormal0(MaterialParameters) ));
|
|
#else
|
|
float3 tempnormal = ClearCoatBottomNormal0(MaterialParameters);
|
|
#endif
|
|
|
|
float2 oct1 = UnitVectorToOctahedron(tempnormal);
|
|
float2 oct3 = ( (oct1 - oct2) * 0.25 ) + (128.0/255.0);
|
|
Payload.CustomData.a = oct3.x;
|
|
Payload.CustomData.z = oct3.y;
|
|
#else
|
|
Payload.CustomData.a = 128.0/255.0;
|
|
Payload.CustomData.z = 128.0/255.0;
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if MATERIAL_SHADINGMODEL_CLOTH
|
|
if (Payload.ShadingModelID == SHADINGMODELID_CLOTH)
|
|
{
|
|
Payload.CustomData = ClothData;
|
|
}
|
|
#endif
|
|
|
|
// Override custom data if sub-surface material
|
|
#if MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || MATERIAL_SHADINGMODEL_EYE
|
|
if (Payload.ShadingModelID == SHADINGMODELID_SUBSURFACE ||
|
|
Payload.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE ||
|
|
Payload.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE ||
|
|
Payload.ShadingModelID == SHADINGMODELID_EYE)
|
|
{
|
|
Payload.CustomData = SubsurfaceData;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
|
|
if (Payload.ShadingModelID == SHADINGMODELID_SINGLELAYERWATER)
|
|
{
|
|
const float3 ScatteringCoeff = max(0.0f, DFDemote(GetSingleLayerWaterMaterialOutput0(MaterialParameters))); // SUBSTRATE_TODO convert to read from SubstrateData when FrontMaterial is plugged in
|
|
const float3 AbsorptionCoeff = max(0.0f, DFDemote(GetSingleLayerWaterMaterialOutput1(MaterialParameters))); // SUBSTRATE_TODO rememeber to check SUBSTRATE_INLINE_SINGLELAYERWATER
|
|
const float PhaseG = clamp(DFDemote(GetSingleLayerWaterMaterialOutput2(MaterialParameters).x), -1.0f, 1.0f);
|
|
|
|
const float3 WaterExtinction = ScatteringCoeff + AbsorptionCoeff;
|
|
const float3 WaterAlbedo = ScatteringCoeff / max(WaterExtinction, 0.000001);
|
|
|
|
Payload.BaseColor.xyz = WaterAlbedo;
|
|
Payload.CustomData.xyz = WaterExtinction;
|
|
Payload.CustomData.w = PhaseG;
|
|
|
|
Payload.Ior = DielectricF0ToIor(DielectricSpecularToF0(Specular));
|
|
Payload.BlendingMode = RAY_TRACING_BLEND_MODE_TRANSLUCENT;
|
|
}
|
|
#endif
|
|
|
|
#if MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
|
|
if (Payload.ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT)
|
|
{
|
|
Payload.CustomData.xyz = GetThinTranslucentMaterialOutput0(MaterialParameters); // SUBSTRATE_TODO convert to read from SubstrateData. We have TransmittancePreCoverage
|
|
}
|
|
#endif
|
|
|
|
#if MATERIAL_USES_ANISOTROPY
|
|
Payload.WorldTangent = WorldTangent;
|
|
Payload.Anisotropy = Anisotropy;
|
|
#endif
|
|
|
|
float3 DiffuseIndirectLighting = 0;
|
|
float3 SubsurfaceIndirectLighting;
|
|
float IndirectIrradiance = 0;
|
|
|
|
float3 VolumetricLightmapBrickTextureUVs;
|
|
|
|
#if PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
|
|
VolumetricLightmapBrickTextureUVs = ComputeVolumetricLightmapBrickTextureUVs(WSHackToFloat(GetWorldPosition(MaterialParameters))); // RT_LWC_TODO
|
|
#endif
|
|
|
|
VTPageTableResult LightmapVTPageTableResult = (VTPageTableResult)0.0f;
|
|
|
|
// Always sample lightmaps without mip biasing, as they are likely packed in an atlas
|
|
// and aggressive bias can cause bleeding between charts.
|
|
float OldGlobalMipBias = GlobalTextureMipBias;
|
|
GlobalTextureMipBias = 0;
|
|
|
|
GetPrecomputedIndirectLightingAndSkyLight(
|
|
MaterialParameters,
|
|
Interpolants,
|
|
LightmapVTPageTableResult,
|
|
Payload.WorldNormal,
|
|
VolumetricLightmapBrickTextureUVs,
|
|
GetShadingModelRequiresBackfaceLighting(Payload.ShadingModelID),
|
|
bIsEnableSkyLightContribution,
|
|
DiffuseIndirectLighting,
|
|
SubsurfaceIndirectLighting,
|
|
IndirectIrradiance);
|
|
|
|
// Restore global mip bias after lightmaps are sampled.
|
|
GlobalTextureMipBias = OldGlobalMipBias;
|
|
|
|
#if MATERIAL_SHADINGMODEL_UNLIT
|
|
if (Payload.ShadingModelID == SHADINGMODELID_UNLIT)
|
|
{
|
|
Payload.Specular = 0;
|
|
Payload.BaseColor = 0;
|
|
Payload.DiffuseColor = 0;
|
|
Payload.SpecularColor = 0;
|
|
Payload.IndirectIrradiance = 0;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Payload.DiffuseColor = BaseColor - BaseColor * Metallic;
|
|
Payload.SpecularColor = ComputeF0(Specular, BaseColor, Metallic);
|
|
Payload.IndirectIrradiance += DiffuseIndirectLighting; // Contains both lightmap & skylight
|
|
}
|
|
}
|
|
#endif // SUBTRATE_GBUFFER_FORMAT==1
|
|
|
|
RAY_TRACING_ENTRY_CLOSEST_HIT(MaterialCHS,
|
|
FPackedMaterialClosestHitPayload, PackedPayload,
|
|
FRayTracingIntersectionAttributes, Attributes)
|
|
{
|
|
PackedPayload.HitT = RayTCurrent();
|
|
|
|
#if USE_MATERIAL_CLOSEST_HIT_SHADER
|
|
GlobalTextureMipBias = PackedPayload.GetMipBias();
|
|
|
|
ResolvedView = ResolveView();
|
|
|
|
FVertexFactoryInterpolantsVSToPS Interpolants;
|
|
const float3 TranslatedWorldPosition = TranslatedWorldRayOrigin() + RayTCurrent() * WorldRayDirection();
|
|
const float4 SvPosition = TranslatedWorldPositionToSvPosition(TranslatedWorldPosition);
|
|
|
|
FRayCone PropagatedCone = PropagateRayCone(PackedPayload.GetRayCone(), 0 /* surface curvature */, RayTCurrent());
|
|
CalcInterpolants(PropagatedCone, Attributes, Interpolants);
|
|
|
|
#if VF_SUPPORTS_RAYTRACING_PREPARE_MATERIAL_PIXEL_PARAMETERS
|
|
float3 GeoNormal = 0;
|
|
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(TranslatedWorldRayOrigin(), WorldRayDirection(), RayTCurrent(), PrimitiveIndex(), Attributes, HitKind(), SvPosition, GeoNormal);
|
|
#else
|
|
float3 GeoNormal = GetGeometryNormalFromTriangleBaseAttributes(PrimitiveIndex());
|
|
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, SvPosition);
|
|
#endif
|
|
|
|
float Dither = 0.5f;
|
|
bool bIsLumenPayload = PackedPayload.IsLumenPayload();
|
|
if (bIsLumenPayload)
|
|
{
|
|
// GetRandom() must be called before SetSceneInstanceIndex because they share the same storage
|
|
Dither = PackedPayload.GetRandom();
|
|
|
|
PackedPayload.SetGeometryNormal(GeoNormal);
|
|
PackedPayload.SetSceneInstanceIndex(GetInstanceUserData());
|
|
}
|
|
|
|
if (PackedPayload.IsMinimalPayloadMode())
|
|
{
|
|
#if MATERIALBLENDING_TRANSLUCENT
|
|
//For shadow ray that does not ignore translucent materials, the material will be evaluated
|
|
// even with minimal payload mode to query the opacity for translucent shadow.
|
|
if (PackedPayload.IsIgnoreTranslucentMaterials() || !PackedPayload.IsShadowRay())
|
|
#endif
|
|
{
|
|
// Minimal payload mode only fills FMinimalPayload::HitT, skipping actual material evaluation.
|
|
// This mode is used when tracing shadow rays against masked geometry.
|
|
// Dynamic branch is used to avoid compiling an extra shader permutation.
|
|
return;
|
|
}
|
|
}
|
|
|
|
CurrentPayloadInputFlags = PackedPayload.GetFlags();
|
|
|
|
FPixelMaterialInputs PixelMaterialInputs;
|
|
|
|
{
|
|
float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition);
|
|
float3 TranslatedWorldPosition = TranslatedWorldRayOrigin() + WorldRayDirection() * RayTCurrent();
|
|
|
|
bool bIsFrontFace = HitKind() == HIT_KIND_TRIANGLE_FRONT_FACE;
|
|
|
|
// #dxr_todo: UE-72130 support world position offset
|
|
// #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
|
|
// CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, BasePassInterpolants.PixelPositionExcludingWPO);
|
|
// #else
|
|
CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, TranslatedWorldPosition);
|
|
// #endif
|
|
}
|
|
|
|
FMaterialClosestHitPayload Payload = (FMaterialClosestHitPayload)0;
|
|
|
|
/**
|
|
* Set common material attributes for both full and simplified materials
|
|
**/
|
|
Payload.ShadingModelID = GetMaterialShadingModel(PixelMaterialInputs);
|
|
|
|
#if MATERIALBLENDING_ALPHACOMPOSITE
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_ALPHA_COMPOSITE;
|
|
#elif MATERIALBLENDING_ALPHAHOLDOUT
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_ALPHA_HOLDOUT;
|
|
#elif MATERIALBLENDING_TRANSLUCENT
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_TRANSLUCENT;
|
|
#elif MATERIALBLENDING_ADDITIVE
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_ADDITIVE;
|
|
#elif MATERIALBLENDING_MODULATE
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_MODULATE;
|
|
#else
|
|
uint MaterialBlendingMode = RAY_TRACING_BLEND_MODE_OPAQUE;
|
|
#endif
|
|
|
|
const uint PrimitiveFlags = GetPrimitiveData(MaterialParameters.PrimitiveId).Flags;
|
|
|
|
Payload.BlendingMode = MaterialBlendingMode;
|
|
Payload.PrimitiveLightingChannelMask = GetPrimitive_LightingChannelMask_FromFlags(PrimitiveFlags);
|
|
|
|
Payload.HitT = RayTCurrent();
|
|
if (HitKind() == HIT_KIND_TRIANGLE_FRONT_FACE)
|
|
{
|
|
Payload.SetFrontFace();
|
|
}
|
|
|
|
#if MATERIAL_TWOSIDED
|
|
Payload.SetTwoSided();
|
|
#endif
|
|
|
|
// Fill payload with material data
|
|
GetMaterialPayload(PixelMaterialInputs, MaterialParameters, Interpolants, PackedPayload.IsEnableSkyLightContribution(), Dither, Payload);
|
|
|
|
// After we have gathered the material info, check to see if we are a holdout to see if we need to overwrite the shaded result
|
|
#if MATERIALBLENDING_ALPHAHOLDOUT
|
|
const bool bIsHoldout = true;
|
|
#else
|
|
const bool bIsHoldout = (PrimitiveFlags & PRIMITIVE_SCENE_DATA_FLAG_HOLDOUT) != 0 && ResolvedView.bPrimitiveAlphaHoldoutEnabled;
|
|
#endif
|
|
const bool bIsCameraRay = PackedPayload.IsCameraRay();
|
|
if (bIsHoldout && bIsCameraRay)
|
|
{
|
|
#if SUBTRATE_GBUFFER_FORMAT==1
|
|
Payload.SubstrateData = (FSubstrateRaytracingPayload)0;
|
|
Payload.ShadingModelID = SHADINGMODELID_UNLIT;
|
|
Payload.Radiance = 0.0;
|
|
Payload.Opacity = 1.0;
|
|
Payload.TransmittancePreCoverage = 0.0;
|
|
#else
|
|
Payload.ShadingModelID = SHADINGMODELID_UNLIT;
|
|
Payload.Radiance = 0.0;
|
|
Payload.BaseColor = 0.0;
|
|
Payload.Specular = 0.0;
|
|
#endif
|
|
Payload.SetHoldout();
|
|
}
|
|
|
|
PackedPayload = PackRayTracingPayload(Payload, PropagatedCone);
|
|
|
|
// Override packed payload with custom Lumen data
|
|
if (bIsLumenPayload)
|
|
{
|
|
PackedPayload.SetSceneInstanceIndex(GetInstanceUserData());
|
|
PackedPayload.SetGeometryNormal(GeoNormal);
|
|
#if SUBTRATE_GBUFFER_FORMAT==1
|
|
// RayCone isn't used by Lumen hit-lighting. Reuse Width to pass IOR back to RGS
|
|
FRayCone IorOverride_Unused;
|
|
IorOverride_Unused.Width = Payload.IorOverride;
|
|
IorOverride_Unused.SpreadAngle = 0;
|
|
PackedPayload.SetRayCone(IorOverride_Unused);
|
|
#endif
|
|
}
|
|
|
|
#if MATERIAL_VIRTUALTEXTURE_FEEDBACK
|
|
if (bIsCameraRay)
|
|
{
|
|
// Virtual texturing feedback logic (camera rays only for now)
|
|
FinalizeVirtualTextureFeedback(
|
|
MaterialParameters.VirtualTextureFeedback,
|
|
MaterialParameters.SvPosition,
|
|
View.VTFeedbackBuffer
|
|
);
|
|
}
|
|
#endif
|
|
|
|
#endif // USE_MATERIAL_CLOSEST_HIT_SHADER
|
|
}
|
|
|
|
RAY_TRACING_ENTRY_ANY_HIT(MaterialAHS,
|
|
FPackedMaterialClosestHitPayload, PackedPayload,
|
|
FRayTracingIntersectionAttributes, Attributes)
|
|
{
|
|
#if USE_MATERIAL_ANY_HIT_SHADER
|
|
|
|
#if MATERIALBLENDING_SOLID
|
|
// Continue traversal by simply returning from this shader
|
|
// Usually this path is inactive because opaque materials don't have AHS bound
|
|
return;
|
|
#else
|
|
// All other blending modes _might_ need material evaluation - so we need
|
|
// to generate some code
|
|
|
|
#if MATERIALBLENDING_MASKED
|
|
// NOTE: Masked mode execute always - regardless of ray flags
|
|
// This ensures that both material rays and shadow rays "see" the same thing
|
|
#else
|
|
// For any other blending models, we have a few options:
|
|
if (PackedPayload.IsIgnoreTranslucentMaterials())
|
|
{
|
|
// special mode used by regular RT shadows - translucent materials are skipped, everything else is treated as opaque
|
|
IgnoreHit();
|
|
return;
|
|
}
|
|
else if (!PackedPayload.IsShadowRay())
|
|
{
|
|
// non-opaque blending mode, but we aren't a shadow ray -- continue to CHS
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// this is a shadow ray and we aren't ignoring translucent materials, so go ahead and run the material logic
|
|
}
|
|
|
|
if (PackedPayload.HitT == RayTCurrent())
|
|
{
|
|
// we have processed this intersection already, ignore it
|
|
IgnoreHit();
|
|
return;
|
|
}
|
|
#endif // !MATERIALBLENDING_MASKED
|
|
|
|
// If we got here -- we have a reason to evaluate the material -- do the setup
|
|
|
|
GlobalTextureMipBias = PackedPayload.GetMipBias();
|
|
|
|
ResolvedView = ResolveView();
|
|
|
|
FVertexFactoryInterpolantsVSToPS Interpolants;
|
|
const float3 TranslatedWorldPosition = TranslatedWorldRayOrigin() + RayTCurrent() * WorldRayDirection();
|
|
const float4 SvPosition = TranslatedWorldPositionToSvPosition(TranslatedWorldPosition);
|
|
|
|
CalcInterpolants(PackedPayload.GetRayCone(), Attributes, Interpolants);
|
|
|
|
#if VF_SUPPORTS_RAYTRACING_PREPARE_MATERIAL_PIXEL_PARAMETERS
|
|
float3 GeoNormal = 0;
|
|
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(TranslatedWorldRayOrigin(), WorldRayDirection(), RayTCurrent(), PrimitiveIndex(), Attributes, HitKind(), SvPosition, GeoNormal);
|
|
#else
|
|
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, SvPosition);
|
|
#endif
|
|
|
|
CurrentPayloadInputFlags = PackedPayload.GetFlags();
|
|
|
|
FPixelMaterialInputs PixelMaterialInputs;
|
|
|
|
{
|
|
float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition);
|
|
float3 TranslatedWorldPosition = TranslatedWorldRayOrigin() + WorldRayDirection() * RayTCurrent();
|
|
|
|
bool bIsFrontFace = HitKind() == HIT_KIND_TRIANGLE_FRONT_FACE;
|
|
|
|
MaterialParameters.CameraVector = -WorldRayDirection();
|
|
|
|
// #dxr_todo: UE-72130 support world position offset
|
|
// #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
|
|
// CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, BasePassInterpolants.PixelPositionExcludingWPO);
|
|
// #else
|
|
CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, TranslatedWorldPosition);
|
|
// #endif
|
|
}
|
|
|
|
// Now extract the relevant info from PixelMaterialInputs according to the blending mode
|
|
#if MATERIALBLENDING_MASKED
|
|
// Regardless of payload flags -- we always apply this
|
|
if (GetMaterialMask(PixelMaterialInputs) < 0)
|
|
{
|
|
IgnoreHit();
|
|
}
|
|
#else // MATERIALBLENDING_MASKED
|
|
|
|
#if SUBTRATE_GBUFFER_FORMAT==1
|
|
#if MATERIAL_IS_SUBSTRATE
|
|
float3 EmissiveLuminance = 0.0f;
|
|
float TotalCoverage = 1.f;
|
|
float3 TransmittancePreCoverage = 0.0f;
|
|
bool bSubstrateSubsurfaceEnable = false;
|
|
const float3 WorldBentNormal0 = GetWorldBentNormalZero(MaterialParameters);
|
|
const float3 CamVector = MaterialParameters.CameraVector;
|
|
|
|
// 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 UnlitSurfaceLuminancePostCoverage = 0.0f;
|
|
float UnlitSurfaceCoverage = 0.0f;
|
|
float3 UnlitSurfaceTransmittancePreCoverage = 0.0f;
|
|
float3 UnlitSurfaceNormal = 0.0f;
|
|
SubstratePixelHeader.SubstrateUpdateTreeUnlit(
|
|
uint2(MaterialParameters.SvPosition.xy),
|
|
CamVector,
|
|
SubstrateData,
|
|
UnlitSurfaceLuminancePostCoverage,
|
|
UnlitSurfaceCoverage,
|
|
UnlitSurfaceTransmittancePreCoverage,
|
|
UnlitSurfaceNormal);
|
|
EmissiveLuminance = UnlitSurfaceLuminancePostCoverage;
|
|
|
|
TotalCoverage = UnlitSurfaceCoverage;
|
|
TransmittancePreCoverage = UnlitSurfaceTransmittancePreCoverage;
|
|
const float3 Transparency = lerp(1, TransmittancePreCoverage, TotalCoverage);
|
|
|
|
#else // SUBSTRATE_OPTIMIZED_UNLIT
|
|
SubstratePixelHeader.IrradianceAO.MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
|
|
SubstratePixelHeader.SetCastContactShadow(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAST_CONTACT_SHADOW);
|
|
SubstratePixelHeader.SetDynamicIndirectShadowCasterRepresentation(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAPSULE_REPRESENTATION);
|
|
|
|
FSubstrateSubsurfaceData SSSData = (FSubstrateSubsurfaceData)0;
|
|
FSubstrateTopLayerData TopLayerData = (FSubstrateTopLayerData)0;
|
|
FSubstrateOpaqueRoughRefractionData OpaqueRoughRefractionData = (FSubstrateOpaqueRoughRefractionData)0;
|
|
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings();
|
|
|
|
// Generate the Substrate material data to write out
|
|
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(0, 0, 0);
|
|
|
|
// Compute TotalCoverage for translucent material
|
|
if (SubstratePixelHeader.SubstrateTree.BSDFCount > 0)
|
|
{
|
|
SubstratePixelHeader.SubstrateUpdateTree(
|
|
SubstrateData,
|
|
CamVector,
|
|
Settings,
|
|
TotalCoverage,
|
|
TransmittancePreCoverage);
|
|
|
|
}
|
|
const float3 Transparency = lerp(1, TransmittancePreCoverage, TotalCoverage);
|
|
|
|
#endif // SUBSTRATE_OPTIMIZED_UNLIT
|
|
#else // MATERIAL_IS_SUBSTRATE
|
|
// SUBSTRATE_TODO: What materials are in this case?
|
|
const float Transparency = 0;
|
|
#endif // MATERIAL_IS_SUBSTRATE
|
|
#else // SUBTRATE_GBUFFER_FORMAT==0
|
|
|
|
#if MATERIALBLENDING_MODULATE
|
|
const float3 Transparency = GetMaterialEmissive(PixelMaterialInputs);
|
|
#elif MATERIALBLENDING_ALPHACOMPOSITE
|
|
const float Opacity = GetMaterialOpacity(PixelMaterialInputs);
|
|
const float Transparency = 1 - Opacity;
|
|
#elif MATERIALBLENDING_TRANSLUCENT
|
|
const float Opacity = GetMaterialOpacity(PixelMaterialInputs);
|
|
#if MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
|
|
float3 Transparency = 1 - Opacity;
|
|
if (Opacity < 1.0)
|
|
{
|
|
float3 Transmission = GetThinTranslucentMaterialOutput0(MaterialParameters);
|
|
float3 V = WorldRayDirection();
|
|
float3 N = normalize(MaterialParameters.WorldNormal);
|
|
float VoN = abs(dot(V, N));
|
|
// compute transmission through the slab (fresnel + absorption)
|
|
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
|
|
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
|
|
float Specular = GetMaterialSpecular(PixelMaterialInputs);
|
|
float F0 = F0RGBToF0(ComputeF0(Specular, BaseColor, Metallic));
|
|
float Ior = GetRefractionIor(PixelMaterialInputs);
|
|
Transparency *= ComputeThinSlabWeights(Transmission, VoN, Ior, F0).Transmitted;
|
|
}
|
|
// Fade out the Transparency as a function of the SurfaceCoverage.
|
|
const float SurfaceCoverage = GetThinTranslucentMaterialOutput1(MaterialParameters);
|
|
Transparency = lerp(1.0.xxx, Transparency, SurfaceCoverage);
|
|
#else // !MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
|
|
float Transparency = 1 - Opacity;
|
|
uint ShadingModelID = GetMaterialShadingModel(PixelMaterialInputs);
|
|
#if MATERIAL_SHADINGMODEL_DEFAULT_LIT && REFRACTION_USE_INDEX_OF_REFRACTION
|
|
if (ShadingModelID == SHADINGMODELID_DEFAULT_LIT)
|
|
{
|
|
float Ior = GetRefractionIor(PixelMaterialInputs);
|
|
if (Transparency > 0 && Ior > 0.0)
|
|
{
|
|
// Material is doing refraction, apply a fake caustic term to represent this
|
|
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
|
|
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
|
|
float Specular = GetMaterialSpecular(PixelMaterialInputs);
|
|
float F0 = F0RGBToF0(ComputeF0(Specular, BaseColor, Metallic));
|
|
float3 N = normalize(MaterialParameters.WorldNormal);
|
|
float NoV = abs(dot(WorldRayDirection(), N));
|
|
float Fr = FresnelReflectance(NoV, Ior, F0);
|
|
Transparency *= Pow2(1 - Fr);
|
|
}
|
|
}
|
|
#endif // MATERIAL_SHADINGMODEL_DEFAULT_LIT
|
|
#endif // !MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
|
|
#endif // MATERIALBLENDING_TRANSLUCENT
|
|
#endif // SUBTRATE_GBUFFER_FORMAT==1
|
|
|
|
float3 ShadowVis = PackedPayload.GetShadowVisibility();
|
|
ShadowVis *= Transparency;
|
|
PackedPayload.SetShadowVisibility(ShadowVis);
|
|
PackedPayload.HitT = RayTCurrent();
|
|
// Keep going if we haven't reached full opacity
|
|
if (any(ShadowVis > 0.0))
|
|
{
|
|
IgnoreHit();
|
|
}
|
|
#endif // !MATERIALBLENDING_MASKED
|
|
|
|
#endif // MATERIALBLENDING_SOLID
|
|
|
|
#endif // USE_MATERIAL_ANY_HIT_SHADER
|
|
}
|