Files
UnrealEngineUWP/Engine/Shaders/BasePassForForwardShadingPixelShader.usf
Nick Penwarden 7c3bba73a1 Fixes for a few iOS rendering bugs.
1) View.ExposureScale is now a float4 instead of a scalar. This appears to workaround an iOS driver bug. This workaround can be moved in to the cross compiler after 4.2.
2) Clamp the number of supported vertex uniform vectors to be at least 256. The engine assumes it has at least 256 to work with for skinned meshes. This prevents a memory overwrite bug. The iOS driver works with more uniforms than it claims to support.
3) Fixed an off-by-one bug in dirty range tracking for global uniform buffers.

[CL 2091350 by Nick Penwarden in Main branch]
2014-06-01 19:09:33 -04:00

248 lines
8.5 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"
#define MATERIAL_NONMETAL 0
/** 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)
half2 c = half2( 0.72134752, 0.25 ) * rcp_a2 + half2( 0.39674113, 0.75 ); // 1 mad
return c.y * exp2( c.x * RoL - c.x ); // 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,
#if ES2_PROFILE && (USE_HDR_MOSAIC || !COMPILER_GLSL_ES2)
in half4 SvPosition : SV_Position,
#endif
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);
#if COMPILER_HLSL // Not sure why this isn't needed everywhere
float2 PixelPos = SvPosition - View.ScreenTexelBias.xy;
MaterialParameters.ScreenPosition.xy = ( PixelPos / View.ViewSizeAndSceneTexelSize.xy - 0.5 ) * float2(2,-2);
MaterialParameters.ScreenPosition.zw = SvPosition.zw;
MaterialParameters.ScreenPosition.xyz *= MaterialParameters.ScreenPosition.w;
#endif
// Store the results in local variables and reuse instead of calling the functions multiple times.
#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 );
#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
#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
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
#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.rgb *= View.ExposureScale.xyz;
#endif
#if OUTPUT_GAMMA_SPACE
OutColor.rgb = sqrt( OutColor.rgb );
#endif
#if ES2_PROFILE && (!OUTPUT_GAMMA_SPACE)
#if COMPILER_GLSL_ES2
#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
}