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

808 lines
33 KiB
Plaintext

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
BasePassPixelShader.usf: Base pass pixel shader
=============================================================================*/
#include "Common.usf"
#include "SHCommon.usf"
#include "BasePassCommon.usf"
#include "Material.usf"
#include "VertexFactory.usf"
#include "LightmapCommon.usf"
#include "ReflectionEnvironmentShared.usf"
#include "BRDF.usf"
#include "Random.usf"
#include "LightAccumulator.usf"
#include "DeferredShadingCommon.usf"
#if TRANSLUCENT_SELF_SHADOWING
#include "ShadowProjectionCommon.usf"
float4x4 WorldToShadowMatrix;
float4 ShadowUVMinMax;
float3 DirectionalLightDirection;
float4 DirectionalLightColor;
#endif
Texture3D TranslucencyLightingVolumeAmbientInner;
SamplerState TranslucencyLightingVolumeAmbientInnerSampler;
Texture3D TranslucencyLightingVolumeAmbientOuter;
SamplerState TranslucencyLightingVolumeAmbientOuterSampler;
Texture3D TranslucencyLightingVolumeDirectionalInner;
SamplerState TranslucencyLightingVolumeDirectionalInnerSampler;
Texture3D TranslucencyLightingVolumeDirectionalOuter;
SamplerState TranslucencyLightingVolumeDirectionalOuterSampler;
// 2nd order SH indirect lighting interpolated from the indirect lighting cache for the whole object
// Used to apply precomputed lighting to translucency
float4 IndirectLightingSHCoefficients[3];
// Bent normal sky shadowing interpolated from the indirect lighting cache for the whole object
float4 PointSkyBentNormal;
#ifndef COMPILER_GLSL
#define COMPILER_GLSL 0
#endif
#define EDITOR_ALPHA2COVERAGE (EDITOR_PRIMITIVE_MATERIAL && FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && !COMPILER_GLSL)
// For now we only use it on EDITOR_PRIMITIVE_MATERIAL (LevelGrid bias can be much lower) but later we might want to use it for all materials.
// According to GCNPerformanceTweets.pdf Tip 38 it might have a performance cost on GCN.
// On consoles we don't need the editor rendering features
#if EDITOR_PRIMITIVE_MATERIAL && FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && !PS4_PROFILE && !XBOXONE_PROFILE
// not available on mobile, if not available we have to reconstruct it from the world position interpolator which is much worse quality (noticable for depth bias)
#define HIGHQUALITY_PS_POSITION 1
#endif
#if TRANSLUCENCY_LIGHTING_SURFACE
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
/** Prenormalized capture of the scene that's closest to the object being rendered, used for reflection environment on translucency. */
TextureCubeArray ReflectionCubemap;
SamplerState ReflectionCubemapSampler;
int CubemapArrayIndex;
#else
TextureCube ReflectionCubemap;
SamplerState ReflectionCubemapSampler;
#endif
half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness, half3 SpecularColor, half IndirectIrradiance)
{
half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness);
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float4 SpecularIBL = TextureCubeArraySampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.ReflectionVector, CubemapArrayIndex, AbsoluteSpecularMip);
#else
float4 SpecularIBL = TextureCubeSampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.ReflectionVector, AbsoluteSpecularMip);
#endif
FLATTEN
if (View.UseLightmaps > 0)
{
// Note: make sure this matches the lightmap mixing done on opaque (ReflectionEnvironmentTiledDeferredMain)
SpecularIBL.rgb *= IndirectIrradiance;
}
#if ENABLE_SKY_LIGHT
BRANCH
if (SkyLightParameters.y > 0 && SpecularIBL.a < .999f)
{
// Normalize for static skylight types which mix with lightmaps
bool bNormalize = SkyLightParameters.z < 1 && View.UseLightmaps;
float3 SkyLighting = GetSkyLightReflection(MaterialParameters.ReflectionVector, Roughness, bNormalize);
FLATTEN
if (bNormalize)
{
SkyLighting *= IndirectIrradiance;
}
// Add in sky wherever reflection captures don't have coverage
SpecularIBL.rgb += (1 - SpecularIBL.a) * SkyLighting;
}
#endif
half NoV = saturate(dot(MaterialParameters.WorldNormal, MaterialParameters.CameraVector));
SpecularColor = EnvBRDFApprox(SpecularColor, Roughness, NoV);
return SpecularIBL.rgb * SpecularColor;
}
#endif
/** Calculates lighting for translucency. */
float3 GetTranslucencyLighting(FMaterialPixelParameters MaterialParameters, float3 DiffuseColor, half Roughness, half3 SpecularColor, float IndirectIrradiance, float MaterialAO)
{
float3 InterpolatedLighting = 0;
// Apply a stable offset to the world position used for lighting, which breaks up artifacts from using a low res volume texture
float3 InnerVolumeUVs = (MaterialParameters.WorldPosition + MaterialParameters.LightingPositionOffset - View.TranslucencyLightingVolumeMin[0].xyz) * View.TranslucencyLightingVolumeInvSize[0].xyz;
float3 OuterVolumeUVs = (MaterialParameters.WorldPosition + MaterialParameters.LightingPositionOffset - View.TranslucencyLightingVolumeMin[1].xyz) * View.TranslucencyLightingVolumeInvSize[1].xyz;
// Controls how fast the lerp between the inner and outer cascades happens
// Larger values result in a shorter transition distance
float TransitionScale = 6;
// Setup a 3d lerp factor going to 0 at the edge of the inner volume
float3 LerpFactors = saturate((.5f - abs(InnerVolumeUVs - .5f)) * TransitionScale);
float FinalLerpFactor = LerpFactors.x * LerpFactors.y * LerpFactors.z;
#if TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE
// Fetch both the ambient and directional values for both cascades
float4 InnerVector0 = Texture3DSampleLevel(TranslucencyLightingVolumeAmbientInner, TranslucencyLightingVolumeAmbientInnerSampler, InnerVolumeUVs, 0);
float3 InnerVector1 = Texture3DSampleLevel(TranslucencyLightingVolumeDirectionalInner, TranslucencyLightingVolumeDirectionalInnerSampler, InnerVolumeUVs, 0).rgb;
float4 OuterVector0 = Texture3DSampleLevel(TranslucencyLightingVolumeAmbientOuter, TranslucencyLightingVolumeAmbientOuterSampler, OuterVolumeUVs, 0);
float3 OuterVector1 = Texture3DSampleLevel(TranslucencyLightingVolumeDirectionalOuter, TranslucencyLightingVolumeDirectionalOuterSampler, OuterVolumeUVs, 0).rgb;
float DirectionalLightingIntensity = GetMaterialTranslucencyDirectionalLightingIntensity();
// Lerp between cascades
// Increase the directional coefficients and attenuate the ambient coefficient based on a tweaked value
float4 Vector0 = lerp(OuterVector0, InnerVector0, FinalLerpFactor) / DirectionalLightingIntensity;
float3 Vector1 = lerp(OuterVector1, InnerVector1, FinalLerpFactor) * DirectionalLightingIntensity;
// Reconstruct the SH coefficients based on what was encoded
FTwoBandSHVectorRGB TranslucentLighting;
TranslucentLighting.R.V.x = Vector0.r;
TranslucentLighting.G.V.x = Vector0.g;
TranslucentLighting.B.V.x = Vector0.b;
float3 NormalizedAmbientColor = Vector0.rgb / Luminance( Vector0.rgb );
// Scale the monocrome directional coefficients with the normalzed ambient color as an approximation to the uncompressed values
TranslucentLighting.R.V.yzw = Vector1.rgb * NormalizedAmbientColor.r;
TranslucentLighting.G.V.yzw = Vector1.rgb * NormalizedAmbientColor.g;
TranslucentLighting.B.V.yzw = Vector1.rgb * NormalizedAmbientColor.b;
// Compute diffuse lighting which takes the normal into account
FTwoBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH(MaterialParameters.WorldNormal, 1);
float4 VolumeLighting = float4(max(half3(0,0,0), DotSH(TranslucentLighting, DiffuseTransferSH)), Vector0.a);
InterpolatedLighting = DiffuseColor * VolumeLighting.rgb;
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
// Lookup the inner and outer cascade ambient lighting values
float4 InnerLighting = Texture3DSampleLevel(TranslucencyLightingVolumeAmbientInner, TranslucencyLightingVolumeAmbientInnerSampler, InnerVolumeUVs, 0);
float4 OuterLighting = Texture3DSampleLevel(TranslucencyLightingVolumeAmbientOuter, TranslucencyLightingVolumeAmbientOuterSampler, OuterVolumeUVs, 0);
// Lerp between cascades
float4 Vector0 = lerp(OuterLighting, InnerLighting, FinalLerpFactor);
// Normal is not taken into account with non directional lighting, and only the ambient term of the SH coefficients are needed
FOneBandSHVectorRGB TranslucentLighting;
TranslucentLighting.R.V.x = Vector0.r;
TranslucentLighting.G.V.x = Vector0.g;
TranslucentLighting.B.V.x = Vector0.b;
FOneBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH1(MaterialParameters.WorldNormal, 1);
float4 VolumeLighting = float4( DotSH1(TranslucentLighting, DiffuseTransferSH), Vector0.a );
// Determine lighting if no self shadowing is applied
InterpolatedLighting = DiffuseColor * VolumeLighting.rgb;
#endif
#if (TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE) && TRANSLUCENT_SELF_SHADOWING
// Only apply self shadowing if the shadow hasn't faded out completely
if (DirectionalLightColor.a > 0)
{
// Determine the shadow space position
// Apply a stable offset to the world position used for shadowing, which blurs out high frequency details in the shadowmap with many layers
float4 HomogeneousShadowPosition = mul(float4(MaterialParameters.WorldPosition + MaterialParameters.LightingPositionOffset, 1), WorldToShadowMatrix);
float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w;
// Lookup the shadow density at the point being shaded
float3 ShadowDensity = CalculateTranslucencyShadowingDensity(ShadowUVs, HomogeneousShadowPosition.z) / GetMaterialTranslucentMultipleScatteringExtinction();
// Compute colored transmission based on the density that the light ray passed through
float3 SelfShadowing = saturate(exp(-ShadowDensity * GetMaterialTranslucentSelfShadowDensityScale()));
// Compute a second shadow gradient to add interesting information in the shadowed area of the first
// This is a stop gap for not having self shadowing from other light sources
float3 SelfShadowing2 = lerp(float3(1, 1, 1), saturate(exp(-ShadowDensity * GetMaterialTranslucentSelfShadowSecondDensityScale())), GetMaterialTranslucentSelfShadowSecondOpacity());
SelfShadowing = SelfShadowing * SelfShadowing2;
// Force unshadowed if we read outside the valid area of the shadowmap atlas
// This can happen if the particle system's bounds don't match its visible area
FLATTEN
if (any(ShadowUVs < ShadowUVMinMax.xy || ShadowUVs > ShadowUVMinMax.zw))
{
SelfShadowing = 1;
}
float3 BackscatteredLighting = 0;
#if MATERIAL_SHADINGMODEL_SUBSURFACE
float InScatterPower = GetMaterialTranslucentBackscatteringExponent();
// Setup a pow lobe to approximate anisotropic in-scattering near to the light direction
float InScattering = pow(saturate(dot(View.DirectionalLightDirection, MaterialParameters.CameraVector)), InScatterPower);
float4 SSData = GetMaterialSubsurfaceData(MaterialParameters);
float3 SubsurfaceColor = SSData.rgb;
BackscatteredLighting =
SubsurfaceColor
* InScattering
* View.DirectionalLightColor.rgb
// Energy normalization, tighter lobes should be brighter
* (InScatterPower + 2.0f) / 8.0f
// Mask by shadowing, exaggerated
* SelfShadowing * SelfShadowing
* VolumeLighting.a;
#endif
// The volume lighting already contains the contribution of the directional light,
// So calculate the amount of light to remove from the volume lighting in order to apply per-pixel self shadowing
// VolumeLighting.a stores all attenuation and opaque shadow factors
float3 SelfShadowingCorrection = DirectionalLightColor.rgb * VolumeLighting.a * (1 - SelfShadowing);
// Combine backscattering and directional light self shadowing
InterpolatedLighting = (BackscatteredLighting + DiffuseColor * max(VolumeLighting.rgb - SelfShadowingCorrection, 0));
}
#endif
#if TRANSLUCENCY_LIGHTING_SURFACE
InterpolatedLighting += GetImageBasedReflectionLighting(MaterialParameters, Roughness, SpecularColor, IndirectIrradiance);
#endif
return InterpolatedLighting;
}
/** Stores the SH ambient term and Coefficient3.x. */
Texture3D IndirectLightingCacheTexture0;
/** Stores Coefficient1 and Coefficient3.y. */
Texture3D IndirectLightingCacheTexture1;
/** Stores Coefficient2 and Coefficient3.z. */
Texture3D IndirectLightingCacheTexture2;
SamplerState IndirectLightingCacheTextureSampler0;
SamplerState IndirectLightingCacheTextureSampler1;
SamplerState IndirectLightingCacheTextureSampler2;
/** Add and Scale to convert world space position into indirect lighting cache volume texture UVs. */
float3 IndirectlightingCachePrimitiveAdd;
float3 IndirectlightingCachePrimitiveScale;
float3 IndirectlightingCacheMinUV;
float3 IndirectlightingCacheMaxUV;
/** Computes sky diffuse lighting, including precomputed shadowing. */
float3 GetSkyLighting(float3 WorldNormal, float2 LightmapUV)
{
float3 Lighting = 0;
#if ENABLE_SKY_LIGHT
float SkyVisibility = 1;
float3 SkyLightingNormal = WorldNormal;
#if HQ_TEXTURE_LIGHTMAP || CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
BRANCH
if (View.SkyLightParameters.x > 0)
{
#if HQ_TEXTURE_LIGHTMAP
// Bent normal from precomputed texture
float4 WorldSkyBentNormalAndOcclusion = GetSkyBentNormalAndOcclusion(LightmapUV * float2(1, 2));
// Renormalize as vector was quantized and compressed
float3 NormalizedBentNormal = normalize(WorldSkyBentNormalAndOcclusion.xyz);
SkyVisibility = WorldSkyBentNormalAndOcclusion.w;
#elif CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
// Bent normal from the indirect lighting cache - one value for the whole object
float3 NormalizedBentNormal = PointSkyBentNormal.xyz;
SkyVisibility = PointSkyBentNormal.w;
#endif
#if (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE) && TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
// NonDirectional lighting can't depend on the normal
SkyLightingNormal = NormalizedBentNormal;
#else
// Weight toward the material normal to increase directionality
float BentNormalWeightFactor = 1 - (1 - SkyVisibility) * (1 - SkyVisibility);
// We are lerping between the inputs of two lighting scenarios based on occlusion
// In the mostly unoccluded case, evaluate sky lighting with the material normal, because it has higher detail
// In the mostly occluded case, evaluate sky lighting with the bent normal, because it is a better representation of the incoming lighting
// Then treat the lighting evaluated along the bent normal as an area light, so we must apply the lambert term
SkyLightingNormal = lerp(NormalizedBentNormal, WorldNormal, BentNormalWeightFactor);
float DotProductFactor = lerp(saturate(dot(NormalizedBentNormal, WorldNormal)), 1, BentNormalWeightFactor);
// Account for darkening due to the geometry term
SkyVisibility *= DotProductFactor;
#endif
}
#endif
// Compute the preconvolved incoming lighting with the bent normal direction
float3 DiffuseLookup = GetSkySHDiffuse(SkyLightingNormal) * View.SkyLightColor.rgb;
// Apply AO to the sky diffuse
Lighting += DiffuseLookup * SkyVisibility;
#endif
return Lighting;
}
/** Calculates indirect lighting contribution on this object from precomputed data. */
float3 GetPrecomputedIndirectLighting(
FMaterialPixelParameters MaterialParameters,
FVertexFactoryInterpolantsVSToPS Interpolants,
FBasePassInterpolantsVSToPS BasePassInterpolants,
out float IndirectIrradiance)
{
IndirectIrradiance = 0;
float3 Lighting = 0;
float2 SkyOcclusionUV = 0;
// Method for movable components which want to use a volume texture of interpolated SH samples
#if CACHED_VOLUME_INDIRECT_LIGHTING
// Compute volume teture UVs from world position
float3 VolumeUVs = MaterialParameters.WorldPosition * IndirectlightingCachePrimitiveScale + IndirectlightingCachePrimitiveAdd;
// Clamp UV to be within the valid region
// Pixels outside of the object's bounding box would read garbage otherwise
VolumeUVs = clamp(VolumeUVs, IndirectlightingCacheMinUV, IndirectlightingCacheMaxUV);
float4 Vector0 = Texture3DSample(IndirectLightingCacheTexture0, IndirectLightingCacheTextureSampler0, VolumeUVs);
// For debugging
#define AMBIENTONLY 0
#if AMBIENTONLY
Lighting = Vector0.rgb / SHAmbientFunction() / PI;
#else
float4 Vector1 = Texture3DSample(IndirectLightingCacheTexture1, IndirectLightingCacheTextureSampler1, VolumeUVs);
float4 Vector2 = Texture3DSample(IndirectLightingCacheTexture2, IndirectLightingCacheTextureSampler2, VolumeUVs);
// Construct the SH environment
FTwoBandSHVectorRGB CachedSH;
CachedSH.R.V = float4(Vector0.x, Vector1.x, Vector2.x, Vector0.w);
CachedSH.G.V = float4(Vector0.y, Vector1.y, Vector2.y, Vector1.w);
CachedSH.B.V = float4(Vector0.z, Vector1.z, Vector2.z, Vector2.w);
// Diffuse convolution
FTwoBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH(MaterialParameters.WorldNormal, 1);
Lighting = max(half3(0,0,0), DotSH(CachedSH, DiffuseTransferSH)) / PI;
#endif
// Method for movable components which want to use a single interpolated SH sample
#elif CACHED_POINT_INDIRECT_LIGHTING
#if TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
FOneBandSHVectorRGB PointIndirectLighting;
PointIndirectLighting.R.V = IndirectLightingSHCoefficients[0].x;
PointIndirectLighting.G.V = IndirectLightingSHCoefficients[1].x;
PointIndirectLighting.B.V = IndirectLightingSHCoefficients[2].x;
FOneBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH1(MaterialParameters.WorldNormal, 1);
Lighting = DotSH1(PointIndirectLighting, DiffuseTransferSH);
#else
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
Lighting = max(half3(0,0,0), DotSH(PointIndirectLighting, DiffuseTransferSH));
#endif
// High quality texture lightmaps
#elif HQ_TEXTURE_LIGHTMAP
float2 LightmapUV0, LightmapUV1;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1);
SkyOcclusionUV = LightmapUV0;
Lighting = GetLightMapColorHQ(LightmapUV0, LightmapUV1, MaterialParameters.WorldNormal).rgb;
// Low quality texture lightmaps
#elif LQ_TEXTURE_LIGHTMAP
float2 LightmapUV0, LightmapUV1;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1);
Lighting = GetLightMapColorLQ( LightmapUV0, LightmapUV1, MaterialParameters.WorldNormal ).rgb;
#endif
// Sky lighting must contribute to IndirectIrradiance for ReflectionEnvironment lightmap mixing
float3 SkyLighting = GetSkyLighting(MaterialParameters.WorldNormal, SkyOcclusionUV);
BRANCH
if( View.UseLightmaps > 0 )
{
Lighting += SkyLighting;
}
else
{
#if TRANSLUCENCY_LIGHTING_SURFACE && FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float DiffuseMip = ComputeReflectionCaptureMipFromRoughness(1);
float4 DiffuseIBL = TextureCubeArraySampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.WorldNormal, CubemapArrayIndex, DiffuseMip);
Lighting += DiffuseIBL.rgb + (1 - DiffuseIBL.a) * SkyLighting;
#endif
}
#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP || CACHED_VOLUME_INDIRECT_LIGHTING || CACHED_POINT_INDIRECT_LIGHTING
Lighting *= View.IndirectLightingColorScale;
IndirectIrradiance = Luminance(Lighting);
#endif
return Lighting;
}
#if EDITOR_PRIMITIVE_MATERIAL
bool bEnableEditorPrimitiveDepthTest;
int MSAASampleCount;
// depth in the red channel in DeviceZ
Texture2D FilteredSceneDepthTexture;
SamplerState FilteredSceneDepthTextureSampler;
#endif
// @return 0:translucent..1:opaque
float ClipForEditorPrimitives(FMaterialPixelParameters MaterialParameters)
{
float Ret = 1;
#if EDITOR_PRIMITIVE_MATERIAL && (FEATURE_LEVEL >= FEATURE_LEVEL_SM4 || ES2_EMULATION)
// Depth test manually if compositing editor primitives since the depth buffer is different (MSAA only)
BRANCH
if (bEnableEditorPrimitiveDepthTest)
{
bool bIsPerspective = (View.ViewToClip._m33 < 1.0f);
// dejitter the sample position and make a filtered lookup - for planes this allows to reconstruct a much less jittery depth comparison function, it however doesn't fix silhuetes
float DeviceZ = Texture2DSampleLevel(FilteredSceneDepthTexture, FilteredSceneDepthTextureSampler, (MaterialParameters.SVPosition.xy - View.TemporalAAParams.zw) * View.ViewSizeAndSceneTexelSize.zw, 0).r;
float PixelDeviceZ = MaterialParameters.SVPosition.z;
// Soft Bias with DeviceZ for best quality
const float DeviceDepthFade = 0.00005f;
// 0.5f is to bias around the actual value, 1 or 0 are another option
Ret = saturate(0.5f - (DeviceZ - PixelDeviceZ) / DeviceDepthFade);
}
#endif
// Note: multiple returns cause strange HLSL compiler error for CV_Coverage in later code
return Ret;
}
#if EDITOR_ALPHA2COVERAGE != 0
uint CustomAlpha2Coverage(inout float4 InOutColor)
{
uint MaskedCoverage = 0xff;
MaskedCoverage = 0;
uint EnabledSampleCount = 1;
// todo: support non 4xMSAA as well
// conservatively on but can be 0 if the opacity is too low
if(InOutColor.a > 0.01f) { MaskedCoverage |= 0x1; }
if(InOutColor.a > 0.25f) { MaskedCoverage |= 0x2; ++EnabledSampleCount; }
if(InOutColor.a > 0.50f) { MaskedCoverage |= 0x4; ++EnabledSampleCount; }
if(InOutColor.a > 0.75f) { MaskedCoverage |= 0x8; ++EnabledSampleCount; }
// renormalize to make this sample the correct weight
InOutColor *= (float)MSAASampleCount / EnabledSampleCount;
return MaskedCoverage;
}
#endif
void Main(
FVertexFactoryInterpolantsVSToPS Interpolants,
FBasePassInterpolantsVSToPS BasePassInterpolants,
#if HIGHQUALITY_PS_POSITION
float4 InSVPosition : SV_POSITION,
#endif
OPTIONAL_IsFrontFace,
out float4 OutColor : SV_Target0
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && (MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !NO_GBUFFER
,out float4 OutGBufferA : SV_Target1
,out float4 OutGBufferB : SV_Target2
,out float4 OutGBufferC : SV_Target3
,out float4 OutGBufferD : SV_Target4
#if ALLOW_STATIC_LIGHTING
,out float4 OutGBufferE : SV_Target5
#endif
#endif
#if EDITOR_ALPHA2COVERAGE != 0
,in uint InCoverage : SV_Coverage
,out uint OutCoverage : SV_Coverage
#endif
)
{
#if EDITOR_ALPHA2COVERAGE != 0
OutCoverage = InCoverage;
#endif
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, BasePassInterpolants.PixelPosition);
CalcMaterialParameters(MaterialParameters,bIsFrontFace,BasePassInterpolants.PixelPosition
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
, BasePassInterpolants.PixelPositionExcludingWPO
#endif
);
#if HIGHQUALITY_PS_POSITION
// SVPosition was already computed but only at low quality.
// Here we override it with the higher quality.
// Pixel position relative to left top of screen (not viewport), center of pixel
// z:DeviceZ, .w:SceneDepth
MaterialParameters.SVPosition = InSVPosition;
#endif
#if EDITOR_PRIMITIVE_MATERIAL && (FEATURE_LEVEL >= FEATURE_LEVEL_SM4 || ES2_EMULATION)
const bool bEditorWeightedZBuffering = true;
#else
const bool bEditorWeightedZBuffering = false;
#endif
//Clip if the blend mode requires it.
if(!bEditorWeightedZBuffering)
{
GetMaterialCoverageAndClipping(MaterialParameters);
}
// 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 );
float MaterialAO = GetMaterialAmbientOcclusion(MaterialParameters);
float Roughness = GetMaterialRoughness(MaterialParameters);
// 0..1, SubsurfaceProfileId = int(x * 255)
float SubsurfaceProfile = 0;
// If we don't use this shading model the color should be black (don't generate shader code for unused data, don't do indirectlighting cache lighting with this color).
float3 SubsurfaceColor = 0;
#if MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE
{
float4 SubsurfaceData = GetMaterialSubsurfaceData(MaterialParameters);
#if MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN
SubsurfaceColor = SubsurfaceData.rgb;
#endif
SubsurfaceProfile = SubsurfaceData.a;
}
#endif
#if MATERIAL_FULLY_ROUGH
Roughness = 1;
#endif
#if USE_DBUFFER && MATERIALDECALRESPONSEMASK && !(MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE || MATERIALBLENDING_MODULATE)
// apply decals from the DBuffer
BRANCH if(Primitive.DecalReceiverMask > 0)
{
float2 NDC = MaterialParameters.ScreenPosition.xy / MaterialParameters.ScreenPosition.w;
float2 ScreenUV = NDC * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
FDBufferData DBufferData = GetDBufferData(ScreenUV);
// the material can disable the DBuffer effects for beter performance or control
if((MATERIALDECALRESPONSEMASK & 0x1) == 0) { DBufferData.PreMulColor = 0; DBufferData.ColorOpacity = 1; }
if((MATERIALDECALRESPONSEMASK & 0x2) == 0) { DBufferData.PreMulWorldNormal = 0; DBufferData.NormalOpacity = 1; }
if((MATERIALDECALRESPONSEMASK & 0x4) == 0) { DBufferData.PreMulRoughness = 0; DBufferData.RoughnessOpacity = 1; }
ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, BaseColor, Metallic, Specular);
}
#endif
// So that the following code can still use DiffuseColor and SpecularColor.
half3 DiffuseColor = BaseColor - BaseColor * Metallic;
half3 SpecularColor = lerp( 0.08 * Specular.xxx, BaseColor, Metallic.xxx );
// todo: COMPILE_SHADERS_FOR_DEVELOPMENT is unfinished feature, using XBOXONE_PROFILE as workaround
#if COMPILE_SHADERS_FOR_DEVELOPMENT == 1 && !XBOXONE_PROFILE && !ES31_AEP_PROFILE
{
// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
DiffuseColor = DiffuseColor * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
SpecularColor = SpecularColor * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.xyz;
}
#endif
half3 Color = 0;
float IndirectIrradiance = 0;
#if !MATERIAL_SHADINGMODEL_UNLIT
Color += GetPrecomputedIndirectLighting(MaterialParameters, Interpolants, BasePassInterpolants, IndirectIrradiance) * (DiffuseColor + SubsurfaceColor) * MaterialAO;
#if SIMPLE_DYNAMIC_LIGHTING
// always unshadowed so BiasedNDotL is not needed
half Lambert = saturate(dot(MaterialParameters.WorldNormal, View.DirectionalLightDirection));
Color += DiffuseColor * Lambert * View.DirectionalLightColor.rgb;
Color += GetMaterialHemisphereLightTransferFull(
DiffuseColor,
MaterialParameters,
View.UpperSkyColor.rgb,
View.LowerSkyColor.rgb
);
#endif
#endif
half Opacity = GetMaterialOpacity(MaterialParameters);
#if NEEDS_BASEPASS_FOGGING
float4 VertexFog = BasePassInterpolants.VertexFog;
#else
float4 VertexFog = float4(0,0,0,1);
#endif
// Volume lighting for lit translucency
#if (MATERIAL_SHADINGMODEL_DEFAULT_LIT || MATERIAL_SHADINGMODEL_SUBSURFACE) && (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE)
Color += GetTranslucencyLighting(MaterialParameters, DiffuseColor, Roughness, SpecularColor, IndirectIrradiance, MaterialAO);
#endif
#if !MATERIAL_SHADINGMODEL_UNLIT
Color = lerp(Color, DiffuseColor + SpecularColor, View.UnlitViewmodeMask);
#endif
half3 Emissive = GetMaterialEmissive(MaterialParameters);
// todo: COMPILE_SHADERS_FOR_DEVELOPMENT is unfinished feature, using XBOXONE_PROFILE as workaround
#if COMPILE_SHADERS_FOR_DEVELOPMENT == 1 && !XBOXONE_PROFILE && !ES31_AEP_PROFILE
// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
#if SM5_PROFILE || SM4_PROFILE
BRANCH
if (View.OutOfBoundsMask > 0)
{
if (any(abs(MaterialParameters.WorldPosition - Primitive.ObjectWorldPositionAndRadius.xyz) > Primitive.ObjectBounds + 1))
{
float Gradient = frac(dot(MaterialParameters.WorldPosition, float3(.577f, .577f, .577f)) / 500.0f);
Emissive = lerp(float3(1,1,0), float3(0,1,1), Gradient.xxx > .5f);
Opacity = 1;
}
}
#endif
#endif
Color += Emissive;
#if MATERIALBLENDING_TRANSLUCENT
OutColor = half4(Color * VertexFog.a + VertexFog.rgb, Opacity);
OutColor = RETURN_COLOR(OutColor);
#elif MATERIALBLENDING_ADDITIVE
OutColor = half4(Color * VertexFog.aaa * Opacity.xxx, 0.0f);
OutColor = RETURN_COLOR(OutColor);
#elif MATERIALBLENDING_MODULATE
// RETURN_COLOR not needed with modulative blending
half3 FoggedColor = lerp(float3(1, 1, 1), Color, VertexFog.aaa * VertexFog.aaa);
OutColor = half4(FoggedColor, Opacity);
#else
// Scene color alpha is used for ScreenSpaceSubsurfaceScattering (if that is not needed it can be disabled with SUBSURFACE_CHANNEL_MODE)
{
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
LightAccumulator_Add(LightAccumulator, Color, 0, 1.0f);
OutColor = RETURN_COLOR(LightAccumulator_GetResult(LightAccumulator));
}
#endif
float4 PrecomputedShadowFactors = GetPrecomputedShadowMasks(Interpolants);
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && (MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !NO_GBUFFER
FGBufferData GBuffer = (FGBufferData)0;
GBuffer.WorldNormal = MaterialParameters.WorldNormal;
GBuffer.BaseColor = BaseColor;
GBuffer.Metallic = Metallic;
GBuffer.Specular = Specular;
GBuffer.Roughness = Roughness;
GBuffer.IndirectIrradiance = IndirectIrradiance;
GBuffer.PrecomputedShadowFactors = PrecomputedShadowFactors;
GBuffer.GBufferAO = MaterialAO;
GBuffer.Opacity = Opacity;
GBuffer.DecalMask = Primitive.DecalReceiverMask;
GBuffer.HasDistanceFieldRepresentation = Primitive.HasDistanceFieldRepresentation;
#if MATERIAL_SHADINGMODEL_UNLIT
GBuffer.ShadingModelID = SHADINGMODELID_UNLIT;
#elif MATERIAL_SHADINGMODEL_DEFAULT_LIT
GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
#elif MATERIAL_SHADINGMODEL_SUBSURFACE
GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE;
GBuffer.CustomData = EncodeSubsurfaceColor(SubsurfaceColor);
#elif MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN
GBuffer.ShadingModelID = SHADINGMODELID_PREINTEGRATED_SKIN;
GBuffer.CustomData = EncodeSubsurfaceColor(SubsurfaceColor);
#elif MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE
GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE_PROFILE;
GBuffer.CustomData = EncodeSubsurfaceProfile(SubsurfaceProfile);
#elif MATERIAL_SHADINGMODEL_CLEAR_COAT
GBuffer.ShadingModelID = SHADINGMODELID_CLEAR_COAT;
float ClearCoat = GetMaterialClearCoat(MaterialParameters);
float ClearCoatRoughness = GetMaterialClearCoatRoughness(MaterialParameters);
float Film = 1 * ClearCoat;
float MetalSpec = 0.9;
float NoV = saturate( dot( MaterialParameters.WorldNormal, MaterialParameters.CameraVector ) );
// Approximation of refraction's effect on EnvBRDF
float RefractionScale = ( (NoV * 0.5 + 0.5) * NoV - 1 ) * saturate( 1.25 - 1.25 * Roughness ) + 1;
RefractionScale = lerp( 1, RefractionScale, ClearCoat );
float3 AbsorptionColor = (1 - Film) + BaseColor * ( Film * (1 / MetalSpec) );
GBuffer.BaseColor = lerp( BaseColor, MetalSpec, Film );
// Approximation of absorption integral, tuned for Roughness=0.4
float3 Absorption = AbsorptionColor * ( (NoV - 1) * 0.85 * ( 1 - lerp( AbsorptionColor, Square(AbsorptionColor), -0.78 ) ) + 1 );
//float Toe = 1 - exp2( -9 * NoV - 3.5 );
//float3 Absorption = Toe * AbsorptionColor * ( (NoV - 1) * 0.85 * ( 1 - lerp( AbsorptionColor, Square(AbsorptionColor), -0.78 ) ) + lerp( 0.93, 0.96, AbsorptionColor * 2 - 1 ) );
GBuffer.BaseColor *= Absorption * lerp( 1, RefractionScale, Metallic );
GBuffer.Specular *= Luminance( Absorption ) * RefractionScale;
GBuffer.CustomData.x = ClearCoat;
GBuffer.CustomData.y = ClearCoatRoughness;
#else
// missing shading model, compiler should report ShadingModelID is not set
#endif
#if !ALLOW_STATIC_LIGHTING
float4 OutGBufferE = 0;
#endif
float QuantizationBias = PseudoRandom( MaterialParameters.SVPosition.xy ) * 0.5 - 0.5;
EncodeGBuffer(GBuffer, OutGBufferA, OutGBufferB, OutGBufferC, OutGBufferD, OutGBufferE, QuantizationBias);
#endif
if(bEditorWeightedZBuffering)
{
OutColor.a = 1;
#if MATERIALBLENDING_MASKED
// some material might have a opacity value
OutColor.a = GetMaterialMaskInputRaw(MaterialParameters);
#endif
// we output premultiplied alpha to we have to darken all 4 channels
OutColor *= ClipForEditorPrimitives(MaterialParameters);
#if EDITOR_ALPHA2COVERAGE != 0
// per MSAA sample
if(MSAASampleCount > 1)
{
OutCoverage = InCoverage & CustomAlpha2Coverage(OutColor);
}
else
{
// no MSAA is handle like per pixel
clip(OutColor.a - GetMaterialOpacityMaskClipValue());
}
#else
// per pixel
clip(OutColor.a - GetMaterialOpacityMaskClipValue());
#endif
}
}