// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= VelocityShader.usf: Calculates velocity vectors. =============================================================================*/ #include "Common.ush" #include "/Engine/Generated/Material.ush" #include "/Engine/Generated/VertexFactory.ush" #include "VelocityCommon.ush" // Move all geometry a little bit towards the camera to not get z fighting with existing depth // buffer of the same meshes rendered with slightly different float computations. // This is a positive number as our z buffer is inverted for better precision. // 0.0f as the isolate code should do a good job to prevent this case (can be increased if that is not the case e.g. if the platform ignores the isolate) static const float GDepthBias = 0.001f; struct FVelocityInterpsVSToPS { #if !TRANSLUCENCY_VELOCITY_FROM_DEPTH // float4(PrevScreenPos.xyzw) float4 PackedVelocityC : TEXCOORD7; #endif FVertexFactoryInterpolantsVSToPS FactoryInterpolants; #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS && !IS_NANITE_PASS float3 PixelPositionExcludingWPO : TEXCOORD8; #endif }; struct FVelocityVSToPS { INVARIANT_OUTPUT float4 Position : SV_POSITION; FVelocityInterpsVSToPS Interps; FStereoVSOutput StereoOutput; }; #define FVertexOutput FVelocityVSToPS #define VertexFactoryGetInterpolants VertexFactoryGetInterpolantsVSToPS /*============================================================================= * Vertex Shader *============================================================================*/ #if VERTEXSHADER void MainVertexShader( FVertexFactoryInput Input, out FVertexOutput Output #if USE_GLOBAL_CLIP_PLANE , out float OutGlobalClipPlaneDistance : SV_ClipDistance #endif ) { StereoSetupVF(Input, Output.StereoOutput); FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input); float4 TranslatedWorldPosition = VertexFactoryGetWorldPosition( Input, VFIntermediates ); #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS && !IS_NANITE_PASS Output.Interps.PixelPositionExcludingWPO = TranslatedWorldPosition.xyz; #endif half3x3 TangentToLocal = VertexFactoryGetTangentToLocal( Input, VFIntermediates ); FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, TranslatedWorldPosition.xyz, TangentToLocal); // Isolate instructions used for world position offset on xbox 360, // As these cause the optimizer to generate different position calculating instructions in each pass, resulting in self-z-fighting. // This is only necessary for shaders used in passes that have depth testing enabled. { TranslatedWorldPosition.xyz += GetMaterialWorldPositionOffset(VertexParameters); ApplyMaterialFirstPersonTransform(VertexParameters, TranslatedWorldPosition.xyz); } Output.Interps.FactoryInterpolants = VertexFactoryGetInterpolants( Input, VFIntermediates, VertexParameters ); float4 PrevTranslatedWorldPosition = VertexFactoryGetPreviousWorldPosition( Input, VFIntermediates ); VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, PrevTranslatedWorldPosition.xyz, TangentToLocal, true); PrevTranslatedWorldPosition.xyz += GetMaterialPreviousWorldPositionOffset(VertexParameters); ApplyMaterialPreviousFirstPersonTransform(VertexParameters, PrevTranslatedWorldPosition.xyz); { // compute the old screen pos with the old world position and the old camera matrix float4 PrevScreenPosObj = mul(float4(PrevTranslatedWorldPosition.xyz, 1), ResolvedView.PrevTranslatedWorldToClip); Output.Position = INVARIANT(mul(float4(TranslatedWorldPosition.xyz, 1), ResolvedView.TranslatedWorldToClip)); #if USE_GLOBAL_CLIP_PLANE OutGlobalClipPlaneDistance = dot(ResolvedView.GlobalClippingPlane, float4(TranslatedWorldPosition.xyz, 1)); #endif #if !TRANSLUCENCY_VELOCITY_FROM_DEPTH Output.Interps.PackedVelocityC = INVARIANT(PrevScreenPosObj); #endif } // Move all geometry a little bit towards the camera (to not get z fighting with existing zbuffer of the same meshes rendered with slightly different float computations). Output.Position.z += View.NumSceneColorMSAASamples > 1 ? GDepthBias * Output.Position.w : 0.0; #if !TRANSLUCENCY_VELOCITY_FROM_DEPTH Output.Interps.PackedVelocityC.z += View.NumSceneColorMSAASamples > 1 ? GDepthBias * Output.Position.w : 0.0; #endif } #endif // VERTEXSHADER /*============================================================================= * Pixel Shader *============================================================================*/ #ifndef VELOCITY_THIN_TRANSLUCENT_MODE #define VELOCITY_THIN_TRANSLUCENT_MODE 0 #endif void MainPixelShader( in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position, FVelocityInterpsVSToPS Input, FStereoPSInput StereoInput OPTIONAL_IsFrontFace OPTIONAL_OutDepthConservative ,out ENCODED_VELOCITY_TYPE OutColor : SV_Target0 #if MATERIALBLENDING_MASKED_USING_COVERAGE , out uint OutCoverage : SV_Coverage #endif ) { StereoSetupPS(StereoInput); // Manual clipping here (alpha-test, etc) FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Input.FactoryInterpolants, SvPosition); FPixelMaterialInputs PixelMaterialInputs; float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition); #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS && !IS_NANITE_PASS float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(SvPosition); CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, TranslatedWorldPosition, Input.PixelPositionExcludingWPO); #else CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, SvPosition, bIsFrontFace); #endif #if OUTPUT_PIXEL_DEPTH_OFFSET ApplyPixelDepthOffsetToMaterialParameters(MaterialParameters, PixelMaterialInputs, OutDepth); #if APPLE_DEPTH_BIAS_HACK OutDepth -= APPLE_DEPTH_BIAS_VALUE; #endif #endif #if MATERIALBLENDING_MASKED_USING_COVERAGE OutCoverage = DiscardMaterialWithPixelCoverage(MaterialParameters, PixelMaterialInputs); #else #if SUBSTRATE_ENABLED const bool bThinTranslucentMaterial = false; FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData(); FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader(); float MaterialOpacity = 1.0f; if (SubstratePixelHeader.ClosureCount > 0) { // Update tree (coverage/transmittance/luminace weights) const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(); const float3 V = MaterialParameters.CameraVector; SubstratePixelHeader.SubstrateUpdateTree(V, Settings); MaterialOpacity = SubstratePixelHeader.SubstrateTree.Operators[SubstrateData.OperatorIndex].Coverage; } #if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE // AlphaComposite - Premultiplied alpha blending MaterialOpacity = GetMaterialOpacity(PixelMaterialInputs); #endif #else const bool bThinTranslucentMaterial = VELOCITY_THIN_TRANSLUCENT_MODE > 0; const float MaterialOpacity = GetMaterialOpacity(PixelMaterialInputs); #endif GetMaterialClippingVelocity(MaterialParameters, PixelMaterialInputs, bThinTranslucentMaterial, MaterialOpacity); #endif #if !TRANSLUCENCY_VELOCITY_FROM_DEPTH // 3d velocity, includes camera an object motion float3 Velocity = Calculate3DVelocity(ScreenPosition, Input.PackedVelocityC); OutColor = EncodeVelocityToTexture(Velocity, (GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_PIXEL_ANIMATION) != 0); #else // We only want velocity generated from camera movement and depth so write zero which is the special clear color value. OutColor = 0; #endif }