// 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 }