Files
UnrealEngineUWP/Engine/Shaders/DeferredDecal.usf
Daniel Wright 1464dcf2c3 Distance field AO using a surface cache
* Provides mid-range stable AO for dynamic rigid meshes
* Movable sky lights are now supported, and distance field AO is used for shadowing Movable sky lighting from dynamic scenes
* Static meshes are preprocessed into signed distance field volumes at mesh build time when the r.AllowMeshDistanceFieldRepresentations project setting is enabled
* Non-uniform scaling does not work with this method (mirroring is fine), animating through world position offset also causes artifacts as the two representations diverge
* Occlusion is computed along cones to reduce over-shadowing, object distance fields are operated on directly (no hierarchy) to obtain enough resolution to prevent leaking, visibility traces are done with cone stepping to allow better parallelization, and shading is done adaptively in space and time using the surface cache.

[CL 2093556 by Daniel Wright in Main branch]
2014-06-03 15:53:13 -04:00

228 lines
6.8 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;
#if DIFFUSE_SPEC_INPUTS
half3 DiffuseColor = GetMaterialDiffuseColor( MaterialParameters );
half3 SpecularColor = GetMaterialSpecularColor( MaterialParameters );
#else
// 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 );
half3 DiffuseColor = BaseColor - BaseColor * Metallic;
half3 SpecularColor = lerp( 0.08 * Specular.xxx, BaseColor, Metallic );
#endif
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;
#if DIFFUSE_SPEC_INPUTS
Data.DiffuseColor = DiffuseColor;
Data.SpecularColor = SpecularColor;
#else
Data.BaseColor = BaseColor;
Data.Metallic = Metallic;
Data.Specular = Specular;
#endif
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