Files
UnrealEngineUWP/Engine/Shaders/DeferredDecal.usf
2014-10-08 15:27:19 -04:00

215 lines
6.4 KiB
Plaintext

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DeferredDecal.usf: Pixel shader for computing a deferred decal.
=============================================================================*/
// DECAL_BLEND_MODE is set by C++ from EDecalBlendMode e.g. DBM_Translucent, DBM_TranslucentColorNormalRoughness, ...
// DECAL_RENDERTARGET_COUNT is set by C++ e.g. 1: single RT, 2: two MRT, 3: three MRT
// DECAL_RENDERSTAGE 0:before BasePass, 1: after base pass, before lighting
#include "Common.usf"
#if DECAL_PROJECTION
#include "Material.usf"
#endif
#include "DeferredShadingCommon.usf" // GBufferData
// from screen space position to decal space (for position)
float4x4 ScreenToDecal;
// from decal space to world space (for normals)
float4x4 DecalToWorld;
// from component to clip space (for decal frustum)
float4x4 FrustumComponentToClip;
void StencilDecalMaskMain(
FScreenVertexOutput Input,
out float4 OutColor : SV_Target0
)
{
FGBufferData InGBufferData = GetGBufferData(Input.UV);
// Write 1 to the stencil buffer for pixels that are masked out of receiving decals
clip(.5f - InGBufferData.DecalMask);
OutColor = 0;
}
// decal vertex shader
void MainVS(
in float4 InPosition : ATTRIBUTE0,
out float4 OutScreenPosition : TEXCOORD0,
out float4 OutPosition : SV_POSITION
)
{
OutPosition = OutScreenPosition = mul(InPosition, FrustumComponentToClip);
}
#if DECAL_PROJECTION
// decal pixel shader
void MainPS(
in float4 ScreenPosition : TEXCOORD0
#if DECAL_RENDERTARGET_COUNT > 0
, out float4 OutTarget0 : SV_Target0
#endif
#if DECAL_RENDERTARGET_COUNT > 1
, out float4 OutTarget1 : SV_Target1
#endif
#if DECAL_RENDERTARGET_COUNT > 2
, out float4 OutTarget2 : SV_Target2
#endif
#if DECAL_RENDERTARGET_COUNT > 3
, out float4 OutTarget3 : SV_Target3
#endif
#if DECAL_RENDERTARGET_COUNT > 4
, out float4 OutTarget4 : SV_Target4
#endif
)
{
half SceneW = PreviousDepth(ScreenPosition);
float4 DecalVector = mul(float4(ScreenPosition.xy / ScreenPosition.w * SceneW, SceneW, 1), ScreenToDecal);
DecalVector.xyz /= DecalVector.w;
// clip content outside the decal
// not needed if we stencil out the decal but we do that only on large (screen space) ones
clip(DecalVector.xyz + 1.0f);
clip(1.0f - DecalVector.xyz);
float4 HomogeneousWorldPosition = mul(float4(ScreenPosition.xy / ScreenPosition.w * SceneW, SceneW, 1), View.ScreenToWorld);
float3 WorldPosition = HomogeneousWorldPosition.xyz / HomogeneousWorldPosition.w;
float3 CameraVector = normalize(View.ViewOrigin.xyz - WorldPosition);
// can be optimized
DecalVector = DecalVector * 0.5f + 0.5f;
// can be optimized
// Swizzle so that DecalVector.xy are perpendicular to the projection direction and DecalVector.z is distance along the projection direction
DecalVector.xyz = DecalVector.zyx;
// By default, map textures using the vectors perpendicular to the projection direction
float2 DecalUVs = DecalVector.xy;
FMaterialPixelParameters MaterialParameters = MakeInitializedMaterialPixelParameters();
#if NUM_MATERIAL_TEXCOORDS
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex++)
{
MaterialParameters.TexCoords[CoordinateIndex] = DecalUVs;
}
#endif
MaterialParameters.VertexColor = 1;
MaterialParameters.CameraVector = CameraVector;
MaterialParameters.ScreenPosition = ScreenPosition;
MaterialParameters.LightVector = DecalVector.xyz;
MaterialParameters.WorldPosition =
MaterialParameters.WorldPosition_CamRelative =
MaterialParameters.WorldPosition_NoOffsets =
MaterialParameters.WorldPosition_NoOffsets_CamRelative = WorldPosition;
{
float3 Normal = GetMaterialNormal(MaterialParameters);
// tangent/decal space to world space
#if MATERIAL_TANGENTSPACENORMAL
MaterialParameters.WorldNormal = normalize(mul(float4(-Normal.z, Normal.y, Normal.x, 0), DecalToWorld).xyz);
#else
MaterialParameters.WorldNormal = normalize(Normal);
#endif
}
MaterialParameters.ReflectionVector = -MaterialParameters.CameraVector + MaterialParameters.WorldNormal * dot(MaterialParameters.WorldNormal, MaterialParameters.CameraVector) * 2.0;
// Store the results in local variables and reuse instead of calling the functions multiple times.
half3 BaseColor = GetMaterialBaseColor( MaterialParameters );
half Metallic = GetMaterialMetallic( MaterialParameters );
half Specular = GetMaterialSpecular( MaterialParameters );
float3 Color = 1;
#if DECAL_BLEND_MODE == 2
// -1..1 range to 0..1
Color = MaterialParameters.WorldNormal * 0.5f + 0.5f;
#else
Color = GetMaterialEmissive(MaterialParameters);
#endif
float Opacity = GetMaterialOpacity(MaterialParameters);
#if 0
// Normal based fade
float3 FaceNormal = normalize( cross( ddx_fine(WorldPosition), ddy_fine(WorldPosition) ) );
float3 DecalZ = mul(float4(-1, 0, 0, 0), DecalToWorld).xyz;
Opacity *= saturate( 2 * dot( FaceNormal, DecalZ ) );
#endif
// Z fade
Opacity *= saturate( 4 - 4 * abs( DecalVector.z * 2 - 1 ) );
// RETURN_COLOR not needed unless writing to SceneColor
OutTarget0 = float4(Color, Opacity);
#if DECAL_RENDERTARGET_COUNT > 1
// some MRT rendering
FGBufferData Data;
Data.WorldNormal = MaterialParameters.WorldNormal;
Data.BaseColor = BaseColor;
Data.Metallic = Metallic;
Data.Specular = Specular;
Data.Roughness = GetMaterialRoughness(MaterialParameters);
Data.CustomData = 0;
Data.IndirectIrradiance = 0;
Data.PrecomputedShadowFactors = 0;
Data.GBufferAO = 1;
Data.Opacity = Opacity;
Data.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
Data.DecalMask = 1;
Data.HasDistanceFieldRepresentation = 1;
#if DECAL_RENDERSTAGE == 0
{
// before base pass (DBuffer)
// @param MultiOpacity .x: Color, .y:Normal, .z:Roughness
float3 MultiOpacity = Data.Opacity;
EncodeDBufferData(Data, MultiOpacity, OutTarget0, OutTarget1, OutTarget2);
}
#elif DECAL_RENDERSTAGE == 1
{
// after base pass, before lighting (GBuffer)
// static lighting isn't updated by decals so we don't need to update that render target
float4 OutTarget5 = 0;
EncodeGBuffer(Data, OutTarget1, OutTarget2, OutTarget3, OutTarget4, OutTarget5);
#if DECAL_BLEND_MODE == 1
// Stain
OutTarget3.rgb *= Opacity;
#endif
OutTarget0.a = Opacity; // Emissive
OutTarget1.a = Opacity; // Normal
OutTarget2.a = Opacity; // Metallic, Specular
OutTarget3.a = Opacity; // BaseColor
OutTarget4.a = Opacity; // Subsurface
}
#endif // DECAL_RENDERSTAGE
#endif //DECAL_RENDERTARGET_COUNT > 1
}
#endif // DECAL_PROJECTION