Files
UnrealEngineUWP/Engine/Shaders/BasePassPixelShader.usf
Daniel Wright bbffb27aaf Fixed specular on movable skylights
* Removed double normalization from stationary skylight specular

[CL 2239230 by Daniel Wright in Main branch]
2014-07-31 19:39:39 -04:00

844 lines
34 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;
#endif
half3 GetImageBasedReflectionLighting(FMaterialPixelParameters MaterialParameters, half Roughness, half3 SpecularColor, half IndirectIrradiance)
{
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness);
float4 SpecularIBL = TextureCubeArraySampleLevel(ReflectionCubemap, ReflectionCubemapSampler, MaterialParameters.ReflectionVector, CubemapArrayIndex, AbsoluteSpecularMip);
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 < .001f)
{
// 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;
#else
return 0;
#endif
}
#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 CACHED_POINT_INDIRECT_LIGHTING
#if TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE
FTwoBandSHVectorRGB PointIndirectLighting;
PointIndirectLighting.R.V = IndirectLightingSHCoefficients[0];
PointIndirectLighting.G.V = IndirectLightingSHCoefficients[1];
PointIndirectLighting.B.V = IndirectLightingSHCoefficients[2];
// Compute diffuse lighting which takes the normal into account
float3 DiffuseGI = max(half3(0,0,0), DotSH(PointIndirectLighting, DiffuseTransferSH));
IndirectIrradiance += Luminance(DiffuseGI);
InterpolatedLighting += DiffuseColor * DiffuseGI * MaterialAO;
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
FOneBandSHVectorRGB PointIndirectLighting;
PointIndirectLighting.R.V = IndirectLightingSHCoefficients[0].x;
PointIndirectLighting.G.V = IndirectLightingSHCoefficients[1].x;
PointIndirectLighting.B.V = IndirectLightingSHCoefficients[2].x;
float3 DiffuseGI = DotSH1(PointIndirectLighting, DiffuseTransferSH);
IndirectIrradiance += Luminance(DiffuseGI);
InterpolatedLighting += DiffuseColor * DiffuseGI * MaterialAO;
#endif
#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 SkyOcclusion = 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);
SkyOcclusion = 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;
SkyOcclusion = 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 - SkyOcclusion) * (1 - SkyOcclusion);
// 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
SkyOcclusion *= 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 * SkyOcclusion;
#endif
return Lighting;
}
/** Calculates indirect lighting contribution on this object. */
float3 GetPrecomputedIndirectLighting(
FMaterialPixelParameters MaterialParameters,
FVertexFactoryInterpolantsVSToPS Interpolants,
FBasePassInterpolantsVSToPS BasePassInterpolants,
out float IndirectIrradiance)
{
IndirectIrradiance = 0;
float3 Lighting = 0;
float2 SkyOcclusionUV = 0;
#define AMBIENTONLY 0
#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);
#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
#elif HQ_TEXTURE_LIGHTMAP
float2 LightmapUV0, LightmapUV1;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1);
SkyOcclusionUV = LightmapUV0;
Lighting = GetLightMapColorHQ(LightmapUV0, LightmapUV1, MaterialParameters.WorldNormal).rgb;
#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.
#if DIFFUSE_SPEC_INPUTS
half3 DiffuseColor = GetMaterialDiffuseColor( MaterialParameters );
half3 SpecularColor = GetMaterialSpecularColor( MaterialParameters );
// prevents negative colors and inconsistent results with lighting in the base pass (should be almost free on PC, on mobile it's more costly so we expect the content creator to fix it)
// could be optimized a bit later but it would be more fragile
DiffuseColor = saturate(DiffuseColor);
SpecularColor = saturate(SpecularColor);
#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 );
// prevents negative colors and inconsistent results with lighting in the base pass (should be almost free on PC, on mobile it's more costly so we expect the content creator to fix it)
// could be optimized a bit later but it would be more fragile
BaseColor = saturate(BaseColor);
Metallic = saturate(Metallic);
#endif
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.Color = 0; DBufferData.ColorOpacity = 1; }
if((MATERIALDECALRESPONSEMASK & 0x2) == 0) { DBufferData.WorldNormal = 0; DBufferData.NormalOpacity = 1; }
if((MATERIALDECALRESPONSEMASK & 0x4) == 0) { DBufferData.Roughness = 0; DBufferData.RoughnessOpacity = 1; }
#if DIFFUSE_SPEC_INPUTS
ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, DiffuseColor, SpecularColor);
#else
ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, BaseColor, Metallic, Specular);
#endif
}
#endif
#if !DIFFUSE_SPEC_INPUTS
// 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 );
#endif
// todo: COMPILE_SHADERS_FOR_DEVELOPMENT is unfinished feature, using XBOXONE_PROFILE as workaround
#if COMPILE_SHADERS_FOR_DEVELOPMENT == 1 && !XBOXONE_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
// 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;
#if DIFFUSE_SPEC_INPUTS
GBuffer.DiffuseColor = DiffuseColor;
GBuffer.SpecularColor = SpecularColor;
#else
GBuffer.BaseColor = BaseColor;
GBuffer.Metallic = Metallic;
GBuffer.Specular = Specular;
#endif
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 );
#if DIFFUSE_SPEC_INPUTS
// Absorption doesn't work correctly with nonmetals with diffuse/spec
float3 AbsorptionColor = (1 - Film) + SpecularColor * ( Film * (1 / MetalSpec) );
GBuffer.SpecularColor = lerp( SpecularColor, MetalSpec, Film );
#else
float3 AbsorptionColor = (1 - Film) + BaseColor * ( Film * (1 / MetalSpec) );
GBuffer.BaseColor = lerp( BaseColor, MetalSpec, Film );
#endif
// 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 ) );
#if DIFFUSE_SPEC_INPUTS
GBuffer.DiffuseColor *= Absorption;
GBuffer.SpecularColor *= Absorption * RefractionScale;
#else
GBuffer.BaseColor *= Absorption * lerp( 1, RefractionScale, Metallic );
GBuffer.Specular *= Luminance( Absorption ) * RefractionScale;
#endif
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
}
}