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

291 lines
10 KiB
Plaintext

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
BasePassForForwardShadingPixelShader.usf: Base pass pixel shader used with forward shading
=============================================================================*/
#include "Common.usf"
#include "BasePassForForwardShadingCommon.usf"
#include "Material.usf"
#include "VertexFactory.usf"
#include "ReflectionEnvironmentShared.usf"
#include "LightmapCommon.usf"
#include "BRDF.usf"
#include "SHCommon.usf"
#include "ShadowFilteringCommon.usf"
/** Prenormalized capture of the scene that's closest to the object being rendered. */
#if !MATERIAL_FULLY_ROUGH
TextureCube ReflectionCubemap;
SamplerState ReflectionCubemapSampler;
#endif
half PhongApprox( half Roughness, half RoL )
{
half a = Roughness * Roughness; // 1 mul
half a2 = a * a; // 1 mul
float rcp_a2 = rcp(a2); // 1 rcp
//half rcp_a2 = exp2( -6.88886882 * Roughness + 6.88886882 );
// Spherical Gaussian approximation: pow( x, n ) ~= exp( (n + 0.775) * (x - 1) )
// Phong: n = 0.5 / a2 - 0.5
// 0.5 / ln(2), 0.275 / ln(2)
half c = 0.72134752 * rcp_a2 + 0.39674113; // 1 mad
return rcp_a2 * exp2( c * RoL - c ); // 2 mad, 1 exp2, 1 mul
// Total 7 instr
}
#if !MATERIAL_FULLY_ROUGH
half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness)
{
half3 ProjectedCaptureVector = MaterialParameters.ReflectionVector;
// Compute fractional mip from roughness
half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness);
// Fetch from cubemap and convert to linear HDR
half3 SpecularIBL = RGBMDecode(ReflectionCubemap.SampleLevel(ReflectionCubemapSampler, ProjectedCaptureVector, AbsoluteSpecularMip), 16.0f);
SpecularIBL *= SpecularIBL;
#if WEBGL
// need a rgb swizzle instead of the existing rgba swizzle, we should add it if another use case comes up.
return SpecularIBL.bgr;
#else
return SpecularIBL;
#endif
}
#endif
half4 IndirectLightingSHCoefficients[3];
half DirectionalLightShadowing;
void Main(
FVertexFactoryInterpolantsVSToPS Interpolants,
FForwardShadingBasePassInterpolantsVSToPS BasePassInterpolants,
in half4 SvPosition : SV_Position,
OPTIONAL_IsFrontFace,
out half4 OutColor : SV_Target0
)
{
#if PACK_INTERPOLANTS
float4 PackedInterpolants[NUM_VF_PACKED_INTERPOLANTS];
VertexFactoryUnpackInterpolants(Interpolants, PackedInterpolants);
#endif
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, BasePassInterpolants.PixelPosition);
CalcMaterialParameters(MaterialParameters, bIsFrontFace, BasePassInterpolants.PixelPosition
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
, BasePassInterpolants.PixelPositionExcludingWPO
#endif
);
//Clip if the blend mode requires it.
GetMaterialCoverageAndClipping(MaterialParameters);
//@mw todo:
//Go over with Brian to determine the proper defines to wrap it and test cases to fix it.
/*
float2 PixelPos = SvPosition - View.ViewRectMin.xy;
MaterialParameters.ScreenPosition.xy = ( PixelPos / View.ViewSizeAndSceneTexelSize.xy - 0.5 ) * float2(2,-2);
MaterialParameters.ScreenPosition.zw = SvPosition.zw;
MaterialParameters.ScreenPosition.xyz *= MaterialParameters.ScreenPosition.w;
*/
// Store the results in local variables and reuse instead of calling the functions multiple times.
// 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 );
#if MATERIAL_NONMETAL
half3 DiffuseColor = BaseColor;
half SpecularColor = 0.04;
#else
half DielectricSpecular = 0.08 * Specular;
half3 DiffuseColor = BaseColor - BaseColor * Metallic; // 1 mad
half3 SpecularColor = (DielectricSpecular - DielectricSpecular * Metallic) + BaseColor * Metallic; // 2 mad
#endif
half Roughness = GetMaterialRoughness(MaterialParameters);
#if MATERIAL_FULLY_ROUGH
// Factors derived from EnvBRDFApprox( SpecularColor, 1, 1 ) == SpecularColor * 0.4524 - 0.0024
DiffuseColor += SpecularColor * 0.45;
SpecularColor = 0;
#else
half NoV = max( dot( MaterialParameters.WorldNormal, MaterialParameters.CameraVector ), 0 );
#if MATERIAL_NONMETAL
// If nothing is hooked up to Metalic and Specular,
// then defaults are the same as a non-metal,
// so this define is safe.
SpecularColor = EnvBRDFApproxNonmetal( Roughness, NoV );
#else
SpecularColor = EnvBRDFApprox( SpecularColor, Roughness, NoV );
#endif
#endif
half3 Color = 0;
half IndirectIrradiance = 0;
#if LQ_TEXTURE_LIGHTMAP
float2 LightmapUV0, LightmapUV1;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1);
half4 LightmapColor = GetLightMapColorLQ( LightmapUV0, LightmapUV1, MaterialParameters.WorldNormal );
Color += LightmapColor.rgb * DiffuseColor;
IndirectIrradiance = LightmapColor.a;
#elif CACHED_POINT_INDIRECT_LIGHTING
#if MATERIALBLENDING_MASKED || MATERIALBLENDING_SOLID
// Take the normal into account for opaque
FTwoBandSHVectorRGB PointIndirectLighting;
PointIndirectLighting.R.V = IndirectLightingSHCoefficients[0];
PointIndirectLighting.G.V = IndirectLightingSHCoefficients[1];
PointIndirectLighting.B.V = IndirectLightingSHCoefficients[2];
FTwoBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH(MaterialParameters.WorldNormal, 1);
// Compute diffuse lighting which takes the normal into account
half3 DiffuseGI = max(half3(0,0,0), DotSH(PointIndirectLighting, DiffuseTransferSH));
IndirectIrradiance = Luminance(DiffuseGI);
Color += DiffuseColor * DiffuseGI;
#else
// Non-directional for translucency
// Ambient terms packed in xyz
// Already divided by PI and SH ambient on CPU
half3 PointIndirectLighting = IndirectLightingSHCoefficients[0];
half3 DiffuseGI = PointIndirectLighting;
IndirectIrradiance = Luminance(DiffuseGI);
Color += DiffuseColor * DiffuseGI;
#endif
#endif
#if !MATERIAL_SHADINGMODEL_UNLIT
half Shadow = GetPrimaryPrecomputedShadowMask(Interpolants).r;
#if SIMPLE_DYNAMIC_LIGHTING
Shadow = DirectionalLightShadowing;
#endif
#if MOVABLE_DIRECTIONAL_LIGHT_CSM
// Cascaded Shadow Map
{
FPCFSamplerSettings Settings;
Settings.ShadowDepthTexture = View.DirectionalLightShadowTexture;
Settings.ShadowDepthTextureSampler = View.DirectionalLightShadowSampler;
Settings.TransitionScale = View.DirectionalLightShadowTransition;
Settings.ShadowBufferSize = View.DirectionalLightShadowSize;
Settings.bSubsurface = false;
Settings.DensityMulConstant = 0;
Settings.ProjectionDepthBiasParameters = 0;
float4 ShadowPosition;
#if MAX_FORWARD_SHADOWCASCADES == 2
{
if (MaterialParameters.ScreenPosition.w >= View.DirectionalLightShadowDistances.x)
{
ShadowPosition = mul(float4(MaterialParameters.ScreenPosition.xyw, 1), View.DirectionalLightScreenToShadow[1]);
}
else
{
ShadowPosition = mul(float4(MaterialParameters.ScreenPosition.xyw, 1), View.DirectionalLightScreenToShadow[0]);
}
}
#else
{
ShadowPosition = mul(float4(MaterialParameters.ScreenPosition.xyw, 1), View.DirectionalLightScreenToShadow[0]);
}
#endif
// Clamp pixel depth in light space for shadowing opaque, because areas of the shadow depth buffer that weren't rendered to will have been cleared to 1
// We want to force the shadow comparison to result in 'unshadowed' in that case, regardless of whether the pixel being shaded is in front or behind that plane
float LightSpacePixelDepthForOpaque = min(ShadowPosition.z, 0.99999f);
Settings.SceneDepth = LightSpacePixelDepthForOpaque;
#if 0
half ShadowMap = Manual1x1PCF(ShadowPosition.xy, Settings);
#else
half ShadowMap = Manual2x2PCF(ShadowPosition.xy, Settings);
#endif
Shadow = min(Shadow, ShadowMap);
}
#endif
half NoL = max(0, dot(MaterialParameters.WorldNormal, View.DirectionalLightDirection));
half RoL = max(0, dot(MaterialParameters.ReflectionVector, View.DirectionalLightDirection));
Color += (Shadow * NoL) * View.DirectionalLightColor.rgb * (DiffuseColor + SpecularColor * PhongApprox(Roughness, RoL));
#if !MATERIAL_FULLY_ROUGH
half3 SpecularIBL = GetImageBasedReflectionLighting(MaterialParameters, Roughness);
// Environment map has been prenormalized, scale by lightmap luminance
Color += SpecularIBL * IndirectIrradiance * SpecularColor;
#endif
#if ENABLE_SKY_LIGHT
//@mw todo
// TODO: Also need to do specular.
Color += GetSkySHDiffuseSimple(MaterialParameters.WorldNormal) * View.SkyLightColor.rgb * DiffuseColor;
#endif
#endif
half Opacity = GetMaterialOpacity(MaterialParameters);
half3 Emissive = GetMaterialEmissive(MaterialParameters);
Color += Emissive;
half4 VertexFog = half4(0, 0, 0, 1);
#if USE_VERTEX_FOG
#if PACK_INTERPOLANTS
VertexFog = PackedInterpolants[0];
#else
VertexFog = BasePassInterpolants.VertexFog;
#endif
#endif
#if MATERIALBLENDING_TRANSLUCENT
OutColor = half4(Color * VertexFog.a + VertexFog.rgb, Opacity);
#elif MATERIALBLENDING_ADDITIVE
OutColor = half4(Color * (VertexFog.a * Opacity.x), 0.0f);
#elif MATERIALBLENDING_MODULATE
half3 FoggedColor = lerp(half3(1, 1, 1), Color, VertexFog.aaa * VertexFog.aaa);
OutColor = half4(FoggedColor, Opacity);
#else
OutColor.rgb = Color * VertexFog.a + VertexFog.rgb;
#if USE_HDR_MOSAIC || OUTPUT_GAMMA_SPACE
// Scene color alpha is not used yet so we set it to 0
OutColor.a = 0.0;
#else
// Place Z in FP16 alpha value.
OutColor.a = BasePassInterpolants.PixelPosition.w;
#endif
#endif
#if !MATERIALBLENDING_MODULATE
// The exposure scale is just a scalar but needs to be a float4 to workaround a driver bug on IOS.
// After 4.2 we can put the workaround in the cross compiler.
OutColor.rgba *= View.ExposureScale.xyzw;
#endif
#if OUTPUT_GAMMA_SPACE
OutColor.rgb = sqrt( OutColor.rgb );
#endif
#if (ES2_PROFILE || ES3_1_PROFILE) && (!OUTPUT_GAMMA_SPACE)
#if COMPILER_GLSL_ES2 || METAL_PROFILE
#if USE_HDR_MOSAIC
OutColor.rgb = HdrMosaic(OutColor.rgb, SvPosition.xy);
#endif
#else
// To enable editor runtime change without recompile, PC always eats the HdrMosaic() cost.
OutColor.rgb = View.HdrMosaic ? HdrMosaic(OutColor.rgb, SvPosition.xy) : OutColor.rgb;
#endif
#endif
}