// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= PostProcessMaterialShaders.usf: Shaders for rendering post process materials =============================================================================*/ #include "Common.ush" #include "ScreenPass.ush" #include "VirtualTextureCommon.ush" #ifndef POST_PROCESS_AR_YCBCR_CONVERSION #define POST_PROCESS_AR_YCBCR_CONVERSION 0 #endif #if POST_PROCESS_AR_YCBCR_CONVERSION #include "ColorUtils.ush" float4x4 YCbCrColorTransform; uint YCbCrSrgbToLinear; #endif #pragma message("UESHADERMETADATA_VERSION 02E0E449-2223-45B4-8CD0-93AB087FBEE3") #ifndef POST_PROCESS_MATERIAL #define POST_PROCESS_MATERIAL 0 #endif #if (POST_PROCESS_MATERIAL == 0) #error POST_PROCESS_MATERIAL must be defined to non-zero in the shader compilation environment. #endif // Must match ESceneTextureId #define PPI_PostProcessInput0 14 #define PPI_PostProcessInput1 15 #define PPI_PostProcessInput2 16 #define PPI_PostProcessInput3 17 #define PPI_PostProcessInput4 18 SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessInput_0) SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessInput_1) SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessInput_2) SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessInput_3) SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessInput_4) SCREEN_PASS_TEXTURE_VIEWPORT(PostProcessOutput) Texture2D PostProcessInput_0_Texture; Texture2D PostProcessInput_1_Texture; Texture2D PostProcessInput_2_Texture; Texture2D PostProcessInput_3_Texture; Texture2D PostProcessInput_4_Texture; SamplerState PostProcessInput_0_Sampler; SamplerState PostProcessInput_1_Sampler; SamplerState PostProcessInput_2_Sampler; SamplerState PostProcessInput_3_Sampler; SamplerState PostProcessInput_4_Sampler; SamplerState PostProcessInput_BilinearSampler; #if SUPPORTS_INDEPENDENT_SAMPLERS #define PostProcessInput_0_SharedSampler PostProcessInput_0_Sampler #define PostProcessInput_1_SharedSampler PostProcessInput_0_Sampler #define PostProcessInput_2_SharedSampler PostProcessInput_0_Sampler #define PostProcessInput_3_SharedSampler PostProcessInput_0_Sampler #define PostProcessInput_4_SharedSampler PostProcessInput_0_Sampler #else #define PostProcessInput_0_SharedSampler PostProcessInput_0_Sampler #define PostProcessInput_1_SharedSampler PostProcessInput_1_Sampler #define PostProcessInput_2_SharedSampler PostProcessInput_2_Sampler #define PostProcessInput_3_SharedSampler PostProcessInput_3_Sampler #define PostProcessInput_4_SharedSampler PostProcessInput_4_Sampler #endif #if MATERIAL_PATH_TRACING_BUFFER_READ SCREEN_PASS_TEXTURE_VIEWPORT(PathTracingPostProcessInput_0) SCREEN_PASS_TEXTURE_VIEWPORT(PathTracingPostProcessInput_1) SCREEN_PASS_TEXTURE_VIEWPORT(PathTracingPostProcessInput_2) SCREEN_PASS_TEXTURE_VIEWPORT(PathTracingPostProcessInput_3) SCREEN_PASS_TEXTURE_VIEWPORT(PathTracingPostProcessInput_4) Texture2D PathTracingPostProcessInput_0_Texture; Texture2D PathTracingPostProcessInput_1_Texture; Texture2D PathTracingPostProcessInput_2_Texture; Texture2D PathTracingPostProcessInput_3_Texture; Texture2D PathTracingPostProcessInput_4_Texture; SamplerState PathTracingPostProcessInput_0_Sampler; SamplerState PathTracingPostProcessInput_1_Sampler; SamplerState PathTracingPostProcessInput_2_Sampler; SamplerState PathTracingPostProcessInput_3_Sampler; SamplerState PathTracingPostProcessInput_4_Sampler; #endif #if PATH_TRACING_POST_PROCESS_MATERIAL // Allow users to customize the behavior of the material for the path tracing with PathTraicngQualitySwitch node bool GetPathTracingQualitySwitch() { return true; } bool GetPathTracingIsShadow() { return false; } bool GetPathTracingIsIndirectDiffuse() { return false; } bool GetPathTracingIsIndirectSpecular() { return false; } bool GetPathTracingIsIndirectVolume() { return false; } #endif #include "NeuralPostProcessCommon.usf" #define EYE_ADAPTATION_LOOSE_PARAMETERS 1 #include "/Engine/Generated/Material.ush" uint ManualStencilReferenceValue; uint ManualStencilTestMask; struct FPostProcessMaterialVSToPS { float4 Position : SV_POSITION; #if NUM_TEX_COORD_INTERPOLATORS float4 TexCoords[(NUM_TEX_COORD_INTERPOLATORS+1)/2] : TEXCOORD0; #endif }; #if NUM_TEX_COORD_INTERPOLATORS float2 GetUV(FPostProcessMaterialVSToPS Interpolants, int UVIndex) { float4 UVVector = Interpolants.TexCoords[UVIndex / 2]; return Mod(UVIndex, 2) == 1 ? UVVector.zw : UVVector.xy; } void SetUV(inout FPostProcessMaterialVSToPS Interpolants, int UVIndex, float2 InValue) { FLATTEN if (Mod(UVIndex, 2) == 1) { Interpolants.TexCoords[UVIndex / 2].zw = InValue; } else { Interpolants.TexCoords[UVIndex / 2].xy = InValue; } } #endif FMaterialVertexParameters GetPostProcessMaterialVSParameters(float2 UV) { // Most params irrelevant so not a lot to fill out here FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters(); Result.VertexColor = 1.f.xxxx; Result.WorldPosition = float3(UV, 0.f); #if NUM_MATERIAL_TEXCOORDS_VERTEX UNROLL for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++) { Result.TexCoords[CoordinateIndex] = UV; } #endif return Result; } #if (FEATURE_LEVEL > FEATURE_LEVEL_ES3_1) #if VERTEXSHADER void MainVS( in float4 InPosition : ATTRIBUTE0, out FPostProcessMaterialVSToPS Output ) { Output = (FPostProcessMaterialVSToPS)0; DrawRectangle(InPosition, Output.Position); #if NUM_TEX_COORD_INTERPOLATORS FMaterialVertexParameters VertexParameters = GetPostProcessMaterialVSParameters(InPosition.xy); float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS]; GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs); GetCustomInterpolators(VertexParameters, CustomizedUVs); { UNROLL for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++) { SetUV(Output, CoordinateIndex, InPosition.xy); } } { UNROLL for (int CoordinateIndex = NUM_MATERIAL_TEXCOORDS; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++) { SetUV(Output, CoordinateIndex, CustomizedUVs[CoordinateIndex]); } } #endif } void MainVS_VideoOverlay( in float4 InPosition : ATTRIBUTE0, in float2 InTexCoord : ATTRIBUTE1, out float2 OutUV : TEXCOORD0, out float4 OutPosition : SV_POSITION ) { DrawRectangle(InPosition, InTexCoord, OutPosition, OutUV); } #elif PIXELSHADER #define STENCIL_TEST_EQUAL 0x1u #define STENCIL_TEST_LESS 0x2u #define STENCIL_TEST_GREATER 0x4u // Perform the stencil test manually by discarding test failure. // This is necessary when Nanite writes custom stencil and the platform cannot support writing arbitrary values directly to // the custom stencil buffer per-pixel void ManualStencilTest(uint2 PixelPos) { const uint Stencil = CalcSceneCustomStencil(PixelPos); const uint Test = (ManualStencilReferenceValue == Stencil ? STENCIL_TEST_EQUAL : 0) | (ManualStencilReferenceValue < Stencil ? STENCIL_TEST_LESS : 0) | (ManualStencilReferenceValue > Stencil ? STENCIL_TEST_GREATER : 0); if ((Test & ManualStencilTestMask) == 0) { discard; } } void MainPS( in FPostProcessMaterialVSToPS Input, out float4 OutColor : SV_Target0 ) { ResolvedView = ResolveView(); FMaterialPixelParameters Parameters = MakeInitializedMaterialPixelParameters(); FPixelMaterialInputs PixelMaterialInputs; // can be optimized float4 SvPosition = Input.Position; float2 ViewportUV = (SvPosition.xy - PostProcessOutput_ViewportMin.xy) * PostProcessOutput_ViewportSizeInverse.xy; #if MANUAL_STENCIL_TEST ManualStencilTest((uint2)SvPosition.xy); #endif #if NUM_TEX_COORD_INTERPOLATORS { UNROLL for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++) { Parameters.TexCoords[CoordinateIndex] = ViewportUV; } } { UNROLL for (int CoordinateIndex = NUM_MATERIAL_TEXCOORDS; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++) { Parameters.TexCoords[CoordinateIndex] = GetUV(Input, CoordinateIndex); } } #endif Parameters.VertexColor = 1; SvPosition.z = LookupDeviceZ(ViewportUVToBufferUV(ViewportUV)); SvPosition.z = max(SvPosition.z, 1e-18); // fill out other related material parameters CalcMaterialParametersPost(Parameters, PixelMaterialInputs, SvPosition, true); #if NEURAL_POSTPROCESS_PREPASS && MATERIAL_NEURAL_POST_PROCESS OutColor = 0.5f; #if HAVE_GetNeuralInput1 float4 Index = GetNeuralInput0(Parameters); float3 NeuralInput0 = GetNeuralInput1(Parameters).rgb; float Mask = GetNeuralInput2(Parameters); const bool bWriteToBuffer = Index.x >= 0; //Configuration the same across all pixels. // Update the source type so we can copy on demand BRANCH if (all((uint2)SvPosition.xy == uint2(0, 0))) { const int SourceType = bWriteToBuffer ? SOURCE_TYPE_BUFFER : SOURCE_TYPE_TEXTURE; UpdateNeuralProfileSourceType(SourceType); } // Write to buffer/texture based on config BRANCH if (Mask != 0) { BRANCH if (bWriteToBuffer) { int Batch = (int)Index.x; int StartChannel = (int)Index.y; float2 BufferWH = Index.zw; SaveToNeuralBuffer(Batch, StartChannel, BufferWH, NeuralInput0); } else { int StartChannel = (int)Index.y; float2 CustomViewportUV = Index.zw; float2 Position = CustomViewportUV * PostProcessOutput_ViewportSize.xy + PostProcessOutput_ViewportMin.xy; if (StartChannel >= 0 && StartChannel <= 2) { RWNeuralTexture[(uint2)Position.xy] = float4(NeuralInput0, 0.0f); } } } // This is for debug only OutColor.xyz = NeuralInput0; #if !MATERIALBLENDING_MODULATE && POST_PROCESS_MATERIAL_BEFORE_TONEMAP && !POST_PROCESS_DISABLE_PRE_EXPOSURE_SCALE OutColor.xyz *= View.PreExposure; #endif return; #endif // HAVE_GetNeuralInput1 #endif // NEURAL_POSTPROCESS_PREPASS // In Unreal, an alpha channel value of 0.0f means that the pixel is opaque and a value of 1.0f means that there is translucency. // This is the opposite of how the alpha channel is interpreted in formats like PNG. For this reason, rendered images that are exported // from the engine will have their alpha channel inverted to match the PNG convention. However, for consistency inside the rendering chain, // we need to stick to 0.0f as the default value. float Alpha = 0.0f; float3 EmissiveColor = 0.0f; #if SUBSTRATE_ENABLED // Post process node forces a single unlit BSDF. We get the raw data from the Substrate post process node from the raw BSDF on the tree. FSubstratePixelHeader SubstratePixelHeader = Parameters.GetFrontSubstrateHeader(); FSubstrateBSDF UnlitBSDF = SubstratePixelHeader.SubstrateTree.BSDFs[0]; UnlitBSDF.SubstrateSanitizeBSDF(); // required wehen not calling SubstrateUpdateTreeUnlit half3 PPColor = BSDF_GETEMISSIVE(UnlitBSDF); half PPAlpha = saturate(1.0 - UNLIT_TRANSMITTANCE(UnlitBSDF).x); // The current interface only allows legacy opacity transformed to transmittance as 1-Opacity. See UMaterialExpressionSubstratePostProcess. // Substrate only use premultiplied alpha blending state (except for modulate and holdout) so we need to convert to the here. #if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED EmissiveColor = PPColor; #elif MATERIALBLENDING_ALPHACOMPOSITE EmissiveColor = PPColor; // Premultipled alpha already baked in by the user #elif MATERIALBLENDING_ALPHAHOLDOUT EmissiveColor = 0.0; #elif MATERIALBLENDING_TRANSLUCENT EmissiveColor = PPColor * PPAlpha; #elif MATERIALBLENDING_ADDITIVE EmissiveColor = PPColor; // not affected by alpha #elif MATERIALBLENDING_MODULATE EmissiveColor = PPColor; // not affected by alpha #else EmissiveColor = PPColor; #endif #if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE // AlphaComposite - Premultiplied alpha blending PPAlpha = GetMaterialOpacity(PixelMaterialInputs); #endif #if MATERIAL_OUTPUT_OPACITY_AS_ALPHA Alpha = PPAlpha; #endif #else // SUBSTRATE_ENABLED // Grab emissive colour as output #if MATERIAL_OUTPUT_OPACITY_AS_ALPHA Alpha = GetMaterialOpacity(PixelMaterialInputs); #endif EmissiveColor = GetMaterialEmissive(PixelMaterialInputs); #endif // SUBSTRATE_ENABLED #ifdef POST_PROCESS_PROPAGATE_ALPHA_INPUT Alpha = SceneTextureLookup(float2(0,0), PPI_PropagatedAlpha, false).r; #endif #if MATERIAL_VIRTUALTEXTURE_FEEDBACK FinalizeVirtualTextureFeedback(Parameters.VirtualTextureFeedback, Parameters.SvPosition, View.VTFeedbackBuffer); #endif OutColor = float4(EmissiveColor, Alpha ); #if !MATERIALBLENDING_MODULATE && POST_PROCESS_MATERIAL_BEFORE_TONEMAP && !POST_PROCESS_DISABLE_PRE_EXPOSURE_SCALE OutColor.xyz *= View.PreExposure; #endif } void MainPS_VideoOverlay( in float2 InUV : TEXCOORD0, in float4 SvPosition : SV_Position, // after all interpolators out float4 OutColor : SV_Target0 ) { ResolvedView = ResolveView(); FMaterialPixelParameters Parameters = MakeInitializedMaterialPixelParameters(); FPixelMaterialInputs PixelMaterialInputs; float2 ViewportUV = InUV; #if NUM_MATERIAL_TEXCOORDS for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex++) { Parameters.TexCoords[CoordinateIndex] = ViewportUV; } #endif Parameters.VertexColor = 1; SvPosition.z = LookupDeviceZ(ViewportUVToBufferUV(ViewportUV)); SvPosition.z = max(SvPosition.z, 1e-18); // fill out other related material parameters CalcMaterialParametersPost(Parameters, PixelMaterialInputs, SvPosition, true); // Grab emissive colour as output #if MATERIAL_OUTPUT_OPACITY_AS_ALPHA const float Alpha = GetMaterialOpacity(PixelMaterialInputs); #else // In Unreal, an alpha channel value of 0.0f means that the pixel is opaque and a value of 1.0f means that there is translucency. // This is the opposite of how the alpha channel is interpreted in formats like PNG. For this reason, rendered images that are exported // from the engine will have their alpha channel inverted to match the PNG convention. However, for consistency inside the rendering chain, // we need to stick to 0.0f as the default value. const float Alpha = 0.0f; #endif OutColor = float4(GetMaterialEmissive(PixelMaterialInputs), Alpha ); } #else // !VERTEXSHADER && !PIXELSHADER #error Wrong shader domain. #endif #else // FEATURE_LEVEL > FEATURE_LEVEL_ES3_1 // // Mobile version // void MainVS( in float4 InPosition : ATTRIBUTE0, in float2 InTexCoord : ATTRIBUTE1, out FPostProcessMaterialVSToPS Output ) { Output = (FPostProcessMaterialVSToPS)0; float2 OutUV; DrawRectangle(InPosition, InTexCoord, Output.Position, OutUV); #if NUM_TEX_COORD_INTERPOLATORS FMaterialVertexParameters VertexParameters = GetPostProcessMaterialVSParameters(InPosition.xy); float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS]; GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs); GetCustomInterpolators(VertexParameters, CustomizedUVs); { UNROLL for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++) { #if POST_PROCESS_AR_PASSTHROUGH SetUV(Output, CoordinateIndex, OutUV); #else SetUV(Output, CoordinateIndex, InPosition.xy); #endif } } { UNROLL for (int CoordinateIndex = NUM_MATERIAL_TEXCOORDS; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++) { SetUV(Output, CoordinateIndex, CustomizedUVs[CoordinateIndex]); } } #endif } void MainPS( in FPostProcessMaterialVSToPS Input, out half4 OutColor : SV_Target0 ) { ResolvedView = ResolveView(); FMaterialPixelParameters Parameters = MakeInitializedMaterialPixelParameters(); FPixelMaterialInputs PixelMaterialInputs; // can be optimized float4 SvPosition = Input.Position; float2 ViewportUV = (SvPosition.xy - PostProcessOutput_ViewportMin.xy) * PostProcessOutput_ViewportSizeInverse.xy; float2 BufferUV = ViewportUVToBufferUV(ViewportUV); #if NUM_TEX_COORD_INTERPOLATORS { UNROLL for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; CoordinateIndex++) { #if POST_PROCESS_AR_PASSTHROUGH Parameters.TexCoords[CoordinateIndex] = GetUV(Input, CoordinateIndex); #else Parameters.TexCoords[CoordinateIndex] = ViewportUV; #endif } } { UNROLL for (int CoordinateIndex = NUM_MATERIAL_TEXCOORDS; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++) { Parameters.TexCoords[CoordinateIndex] = GetUV(Input, CoordinateIndex); } } #endif Parameters.VertexColor = 1; float ClipValue = 1.0f; float DeviceZ = LookupDeviceZ(BufferUV); SvPosition.z = DeviceZ; SvPosition.z = max(SvPosition.z, 1e-18); // fill out other related material parameters CalcMaterialParametersPost(Parameters, PixelMaterialInputs, SvPosition, true); float Alpha = 0.0f; float3 EmissiveColor = 0.0f; #if SUBSTRATE_ENABLED // Unlit forces a single BSDF FSubstrateBSDF UnlitBSDF = PixelMaterialInputs.FrontMaterial.InlinedBSDF; UnlitBSDF.SubstrateSanitizeBSDF(); half3 PPColor = BSDF_GETEMISSIVE(UnlitBSDF); half PPAlpha = saturate(1.0 - UNLIT_TRANSMITTANCE(UnlitBSDF).x); // The current interface only allows legacy opacity transformed to transmittance as 1-Opacity. See UMaterialExpressionSubstratePostProcess. // Substrate only use premultiplied alpha blending state (except for modulate and holdout) so we need to convert to the here. #if MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED EmissiveColor = PPColor; #elif MATERIALBLENDING_ALPHACOMPOSITE EmissiveColor = PPColor; // Premultipled alpha already baked in by the user #elif MATERIALBLENDING_ALPHAHOLDOUT EmissiveColor = 0.0; #elif MATERIALBLENDING_TRANSLUCENT EmissiveColor = PPColor * PPAlpha; #elif MATERIALBLENDING_ADDITIVE EmissiveColor = PPColor; // not affected by alpha #elif MATERIALBLENDING_MODULATE EmissiveColor = PPColor; // not affected by alpha #else EmissiveColor = PPColor; #endif #if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE // AlphaComposite - Premultiplied alpha blending PPAlpha = GetMaterialOpacity(PixelMaterialInputs); #endif #if MATERIAL_OUTPUT_OPACITY_AS_ALPHA Alpha = PPAlpha; #endif #else // SUBSTRATE_ENABLED // Grab emissive colour as output EmissiveColor = GetMaterialEmissive(PixelMaterialInputs); #if POST_PROCESS_AR_YCBCR_CONVERSION const float3 YCbCr = EmissiveColor.yzx; EmissiveColor.rgb = YuvToRgb(YCbCr, YCbCrColorTransform, YCbCrSrgbToLinear); #endif #if MATERIAL_OUTPUT_OPACITY_AS_ALPHA Alpha = GetMaterialOpacity(PixelMaterialInputs); #else Alpha = 0.0f; #endif #endif // SUBSTRATE_ENABLED #if MATERIAL_VIRTUALTEXTURE_FEEDBACK FinalizeVirtualTextureFeedback(Parameters.VirtualTextureFeedback, Parameters.SvPosition, View.VTFeedbackBuffer); #endif half4 FullSceneColor = half4(EmissiveColor, Alpha); #if POST_PROCESS_MATERIAL_BEFORE_TONEMAP #if OUTPUT_GAMMA_SPACE FullSceneColor.rgb = sqrt(FullSceneColor.rgb); #endif #if !MATERIALBLENDING_MODULATE FullSceneColor.xyz *= View.PreExposure; #endif #endif OutColor = FullSceneColor; } #endif // FEATURE_LEVEL > FEATURE_LEVEL_ES3_1