Files
UnrealEngineUWP/Engine/Shaders/Private/ReflectionEnvironmentShaders.usf
zach bethel 51d195d21f Major refactor of reflection capture code.
- Converted to RDG.
 - Converted mobile to use subresource transitions instead of awkward ping-ponging between render targets.
 - Merged duplicate code paths between mobile / desktop.
 - Eliminated FReflectionScratchCubemaps singleton in favor of explicit resource marshalling.

#preflight 623cdecc573f51b292c9c84a
#rb christopher.waters

[CL 19513281 by zach bethel in ue5-main branch]
2022-03-25 11:17:23 -04:00

724 lines
24 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
=============================================================================*/
#include "Common.ush"
#include "DeferredShadingCommon.ush"
#include "BRDF.ush"
#include "SHCommon.ush"
#include "ReflectionEnvironmentShared.ush"
#include "MonteCarlo.ush"
#include "SkyLightingShared.ush"
struct FCopyToCubeFaceVSOutput
{
float2 UV : TEXCOORD0;
float3 ScreenVector : TEXCOORD1;
float4 Position : SV_POSITION;
};
void CopyToCubeFaceVS(
in float2 InPosition : ATTRIBUTE0,
in float2 InUV : ATTRIBUTE1,
out FCopyToCubeFaceVSOutput Out
)
{
DrawRectangle(float4(InPosition.xy, 0, 1), InUV, Out.Position, Out.UV);
Out.ScreenVector = mul(float4(Out.Position.xy, 1, 0), View.ScreenToTranslatedWorld).xyz;
}
int CubeFace;
Texture2D SceneColorTexture;
SamplerState SceneColorSampler;
#if !SHADING_PATH_DEFERRED
Texture2D SceneDepthTexture;
#endif
SamplerState SceneDepthSampler;
/**
* X = 0 if capturing sky light, 1 if capturing reflection capture with MaxDistance fade, 2 otherwise,
* Y = Sky distance threshold,
* Z = whether a skylight's lower hemisphere should be replaced with LowerHemisphereColor.
*/
float4 SkyLightCaptureParameters;
float4 LowerHemisphereColor;
void CopySceneColorToCubeFaceColorPS(
FCopyToCubeFaceVSOutput Input,
out float4 OutColor : SV_Target0
)
{
float SceneDepth = SCENE_TEXTURES_DISABLED_SCENE_DEPTH_VALUE;
#if !SCENE_TEXTURES_DISABLED
SceneDepth = ConvertFromDeviceZ(Texture2DSample(SceneDepthTexture, SceneDepthSampler, Input.UV).r);
#endif
float3 SceneColor = Texture2DSample(SceneColorTexture, SceneColorSampler, Input.UV).rgb;
// Convert INF's to valid values
SceneColor = ClampToHalfFloatRange(SceneColor);
float3 TranslatedWorldPosition = Input.ScreenVector * SceneDepth + View.TranslatedWorldCameraOrigin;
float Alpha = 1;
if (SkyLightCaptureParameters.x == 0)
{
// Assuming we're on a planet and no sky lighting is coming from below the horizon
// This is important to avoid leaking from below since we are integrating incoming lighting and shadowing separately
if (Input.ScreenVector.z < 0 && SkyLightCaptureParameters.z >= 1)
{
SceneColor = lerp(SceneColor, LowerHemisphereColor.rgb, LowerHemisphereColor.a);
}
}
else if (SkyLightCaptureParameters.x == 1)
{
float RadialDistance = length(TranslatedWorldPosition - View.TranslatedWorldCameraOrigin);
float MaxDistance = SkyLightCaptureParameters.y;
// Setup alpha to fade out smoothly past the max distance
// This allows a local reflection capture to only provide reflections where it has valid data, falls back to sky cubemap
Alpha = 1 - smoothstep(.8f * MaxDistance, MaxDistance, RadialDistance);
}
// We need pre-multiplied alpha for correct filtering
// However, we need to compute average brightness before masking out sky areas, so premultiplying happens later
OutColor = float4(SceneColor, Alpha);
}
float3 GetCubemapVector(float2 ScaledUVs, int InCubeFace)
{
float3 CubeCoordinates;
//@todo - this could be a 3x3 matrix multiply
if (InCubeFace == 0)
{
CubeCoordinates = float3(1, -ScaledUVs.y, -ScaledUVs.x);
}
else if (InCubeFace == 1)
{
CubeCoordinates = float3(-1, -ScaledUVs.y, ScaledUVs.x);
}
else if (InCubeFace == 2)
{
CubeCoordinates = float3(ScaledUVs.x, 1, ScaledUVs.y);
}
else if (InCubeFace == 3)
{
CubeCoordinates = float3(ScaledUVs.x, -1, -ScaledUVs.y);
}
else if (InCubeFace == 4)
{
CubeCoordinates = float3(ScaledUVs.x, -ScaledUVs.y, 1);
}
else
{
CubeCoordinates = float3(-ScaledUVs.x, -ScaledUVs.y, -1);
}
return CubeCoordinates;
}
float CubeTexelWeight( float3 N )
{
uint Axis = 2;
if( abs(N.x) >= abs(N.y) && abs(N.x) >= abs(N.z) )
{
Axis = 0;
}
else if( abs(N.y) > abs(N.z) )
{
Axis = 1;
}
N = Axis == 0 ? N.zyx : N;
N = Axis == 1 ? N.xzy : N;
float2 UV = N.xy / N.z;
float VecLengthSqr = 1 + dot( UV, UV );
return 4.0 / ( sqrt( VecLengthSqr ) * VecLengthSqr );
}
TextureCube SourceCubemapTexture;
SamplerState SourceCubemapSampler;
float2 SinCosSourceCubemapRotation;
float2 SvPositionToUVScale;
void CopyCubemapToCubeFaceColorPS(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float2 UV = SvPosition.xy * SvPositionToUVScale;
float2 ScaledUVs = UV * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
// Rotate around Z axis
CubeCoordinates.xy = float2(dot(CubeCoordinates.xy, float2(SinCosSourceCubemapRotation.y, -SinCosSourceCubemapRotation.x)), dot(CubeCoordinates.xy, SinCosSourceCubemapRotation));
OutColor = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, CubeCoordinates, 0);
if (SkyLightCaptureParameters.x > 0)
{
// Assuming we're on a planet and no sky lighting is coming from below the horizon
// This is important to avoid leaking from below since we are integrating incoming lighting and shadowing separately
if (CubeCoordinates.z < 0 && SkyLightCaptureParameters.z >= 1)
{
OutColor.rgb = lerp(OutColor.rgb, LowerHemisphereColor.rgb, LowerHemisphereColor.a);
}
}
OutColor.a = 1;
}
uint MipIndex;
uint NumMips;
#ifdef USE_COMPUTE
int FaceThreadGroupSize;
int2 ValidDispatchCoord;
RWTextureCube<float4> OutTextureMipColor; // All slices, i.e. faces, of a cube map mip level
#endif
#ifdef USE_COMPUTE
[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
void DownsampleCS(uint3 ThreadId : SV_DispatchThreadID)
{
const uint2 FaceCoord = uint2(ThreadId.x % uint(FaceThreadGroupSize), ThreadId.y);
if (any(FaceCoord >= uint2(ValidDispatchCoord)))
{
return;
}
const int SelectedCubeFace = int(ThreadId.x) / FaceThreadGroupSize;
float2 ScaledUVs = ((float2(FaceCoord) + 0.5f) / float2(ValidDispatchCoord)) * 2.0f - 1.0f;
float4 OutColor;
#else // USE_COMPUTE
void DownsamplePS(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float2 UV = SvPosition.xy * SvPositionToUVScale;
float2 ScaledUVs = UV * 2 - 1;
const int SelectedCubeFace = CubeFace;
#endif // USE_COMPUTE
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
uint MipSize = 1u << ( NumMips - MipIndex - 1 );
float3 TangentZ = normalize( CubeCoordinates );
float3 TangentX = normalize( cross( GetCubemapVector( ScaledUVs + float2(0,1), SelectedCubeFace), TangentZ ) );
float3 TangentY = cross( TangentZ, TangentX );
const float SampleOffset = 2.0 * 2 / MipSize;
float2 Offsets[] =
{
float2(-1, -1) * 0.7,
float2( 1, -1) * 0.7,
float2(-1, 1) * 0.7,
float2( 1, 1) * 0.7,
float2( 0, -1),
float2(-1, 0),
float2( 1, 0),
float2( 0, 1),
};
OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
UNROLL
for( uint i = 0; i < 8; i++ )
{
float Weight = 0.375;
float3 SampleDir = CubeCoordinates;
SampleDir += TangentX * ( Offsets[i].x * SampleOffset );
SampleDir += TangentY * ( Offsets[i].y * SampleOffset );
OutColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, SampleDir, 0 ) * Weight;
}
OutColor *= rcp( 1.0 + 1.0 + 2.0 );
#ifdef USE_COMPUTE
OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
#endif
}
#ifdef USE_COMPUTE
float4 LowerHemisphereSolidColor;
[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
void ApplyLowerHemisphereColorCS(uint3 ThreadId : SV_DispatchThreadID)
{
const uint2 FaceCoord = uint2(ThreadId.x % uint(FaceThreadGroupSize), ThreadId.y);
if (any(FaceCoord >= uint2(ValidDispatchCoord)))
{
return;
}
const int SelectedCubeFace = int(ThreadId.x) / FaceThreadGroupSize;
float2 ScaledUVs = ((float2(FaceCoord) + 0.5f) / float2(ValidDispatchCoord)) * 2.0f - 1.0f;
float4 OutColor;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
float3 N = normalize(CubeCoordinates);
if (N.z < 0.0f)
{
OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = float4(LowerHemisphereSolidColor.rgb * LowerHemisphereSolidColor.a, 1.0f);
}
}
#endif
int NumCaptureArrayMips;
/** Cube map array of reflection captures. */
TextureCube ReflectionEnvironmentColorTexture;
SamplerState ReflectionEnvironmentColorSampler;
#if COMPUTEBRIGHTNESS_PIXELSHADER
void ComputeBrightnessMain(out float4 OutColor : SV_Target0)
{
// Sample the 6 1x1 cube faces and average
float3 AverageColor = TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(1, 0, 0), NumCaptureArrayMips - 1).rgb;
AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(-1, 0, 0), NumCaptureArrayMips - 1).rgb;
AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 1, 0), NumCaptureArrayMips - 1).rgb;
AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, -1, 0), NumCaptureArrayMips - 1).rgb;
AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, 1), NumCaptureArrayMips - 1).rgb;
AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, -1), NumCaptureArrayMips - 1).rgb;
OutColor = dot(AverageColor / 6, .3333f);
}
#endif
float4 SampleCubemap(float3 Coordinates, uint InMipIndex)
{
return TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, Coordinates, InMipIndex);
}
uint SourceMipIndex;
float4 SampleCubemap(float3 Coordinates)
{
return SampleCubemap(Coordinates, SourceMipIndex);
}
void DownsamplePS_Mobile(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float2 UV = SvPosition.xy * SvPositionToUVScale;
float2 ScaledUVs = UV * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
OutColor = SampleCubemap(CubeCoordinates);
}
#ifdef USE_COMPUTE
int CubeFaceOffset;
[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
void FilterCS(uint3 ThreadId : SV_DispatchThreadID)
{
const uint2 FaceCoord = uint2(ThreadId.x % uint(FaceThreadGroupSize), ThreadId.y);
if (any(FaceCoord >= uint2(ValidDispatchCoord)))
{
return;
}
const int SelectedCubeFace = CubeFaceOffset + int(ThreadId.x) / FaceThreadGroupSize;
float2 ScaledUVs = ((float2(FaceCoord) + 0.5f) / float2(ValidDispatchCoord)) * 2.0f - 1.0f;
float4 OutColor;
#else // USE_COMPUTE
void FilterPS(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float2 UV = SvPosition.xy * SvPositionToUVScale;
float2 ScaledUVs = UV * 2 - 1;
const int SelectedCubeFace = CubeFace;
#endif // USE_COMPUTE
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
float3 N = normalize(CubeCoordinates);
float3x3 TangentToWorld = GetTangentBasis( N );
float Roughness = ComputeReflectionCaptureRoughnessFromMip( MipIndex, NumMips - 1 );
if( Roughness < 0.01 )
{
OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
#ifdef USE_COMPUTE
OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
#endif
return;
}
uint CubeSize = 1u << ( NumMips - 1 );
const float SolidAngleTexel = 4.0f * PI / float(6 * CubeSize * CubeSize) * 2.0f;
//const uint NumSamples = 1024;
const uint NumSamples = Roughness < 0.1 ? 32 : 64;
float4 FilteredColor = 0;
BRANCH
if( Roughness > 0.99 )
{
// Roughness=1, GGX is constant. Use cosine distribution instead
LOOP
for( uint i = 0; i < NumSamples; i++ )
{
float2 E = Hammersley( i, NumSamples, 0 );
float3 L = CosineSampleHemisphere( E ).xyz;
float NoL = L.z;
float PDF = NoL / PI;
float SolidAngleSample = 1.0 / ( NumSamples * PDF );
float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
L = mul( L, TangentToWorld );
FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip );
}
OutColor = FilteredColor / NumSamples;
}
else
{
float Weight = 0;
LOOP
for( uint i = 0; i < NumSamples; i++ )
{
float2 E = Hammersley( i, NumSamples, 0 );
// 6x6 Offset rows. Forms uniform star pattern
//uint2 Index = uint2( i % 6, i / 6 );
//float2 E = ( Index + 0.5 ) / 5.8;
//E.x = frac( E.x + (Index.y & 1) * (0.5 / 6.0) );
E.y *= 0.995;
float3 H = ImportanceSampleGGX( E, Pow4(Roughness) ).xyz;
float3 L = 2 * H.z * H - float3(0,0,1);
float NoL = L.z;
float NoH = H.z;
if( NoL > 0 )
{
//float TexelWeight = CubeTexelWeight( L );
//float SolidAngleTexel = SolidAngleAvgTexel * TexelWeight;
//float PDF = D_GGX( Pow4(Roughness), NoH ) * NoH / (4 * VoH);
float PDF = D_GGX( Pow4(Roughness), NoH ) * 0.25;
float SolidAngleSample = 1.0 / ( NumSamples * PDF );
float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
float ConeAngle = acos( 1 - SolidAngleSample / (2*PI) );
L = mul( L, TangentToWorld );
FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip ) * NoL;
Weight += NoL;
}
}
OutColor = FilteredColor / Weight;
}
#ifdef USE_COMPUTE
OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
#endif
}
float4 CoefficientMask0;
float4 CoefficientMask1;
float CoefficientMask2;
int NumSamples;
void DiffuseIrradianceCopyPS(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float2 UV = SvPosition.xy * SvPositionToUVScale;
float2 ScaledUVs = UV * 2 - 1;
float3 CubeCoordinates = normalize(GetCubemapVector(ScaledUVs, CubeFace));
float SquaredUVs = 1 + dot(ScaledUVs, ScaledUVs);
// Dividing by NumSamples here to keep the sum in the range of fp16, once we get down to the 1x1 mip
float TexelWeight = 4 / (sqrt(SquaredUVs) * SquaredUVs);
FThreeBandSHVector SHCoefficients = SHBasisFunction3(CubeCoordinates);
float CurrentSHCoefficient = dot(SHCoefficients.V0, CoefficientMask0) + dot(SHCoefficients.V1, CoefficientMask1) + SHCoefficients.V2 * CoefficientMask2;
float3 TexelLighting = SampleCubemap(CubeCoordinates).rgb;
OutColor = float4(TexelLighting * CurrentSHCoefficient * TexelWeight, TexelWeight);
}
float4 Sample01;
float4 Sample23;
void DiffuseIrradianceAccumulatePS(
float4 SvPosition : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float4 AccumulatedValue = 0;
float2 UV = SvPosition.xy * SvPositionToUVScale;
{
float2 ScaledUVs = saturate(UV + Sample01.xy) * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
AccumulatedValue += SampleCubemap(CubeCoordinates);
}
{
float2 ScaledUVs = saturate(UV + Sample01.zw) * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
AccumulatedValue += SampleCubemap(CubeCoordinates);
}
{
float2 ScaledUVs = saturate(UV + Sample23.xy) * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
AccumulatedValue += SampleCubemap(CubeCoordinates);
}
{
float2 ScaledUVs = saturate(UV + Sample23.zw) * 2 - 1;
float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
AccumulatedValue += SampleCubemap(CubeCoordinates);
}
OutColor = float4(AccumulatedValue.rgb / 4.0f, AccumulatedValue.a / 4.0f);
}
void AccumulateCubeFacesPS(
out float4 OutColor : SV_Target0
)
{
float4 AccumulatedValue;
AccumulatedValue = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(1, 0, 0), SourceMipIndex);
AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(-1, 0, 0), SourceMipIndex);
AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 1, 0), SourceMipIndex);
AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, -1, 0), SourceMipIndex);
AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, 1), SourceMipIndex);
AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, -1), SourceMipIndex);
OutColor = float4(4 * PI * AccumulatedValue.rgb / ( max(AccumulatedValue.a, .00001f)), 0);
}
#ifdef SHADER_DIFFUSE_TO_SH
#include "SHCommon.ush"
#include "MonteCarlo.ush"
RWStructuredBuffer<float4> OutIrradianceEnvMapSH;
float UniformSampleSolidAngle;
#define THREADGROUP_SIZE (THREADGROUP_SIZE_X * THREADGROUP_SIZE_Y)
groupshared FThreeBandSHVectorRGB IrradianceSHShared[THREADGROUP_SIZE];
FThreeBandSHVectorRGB SampleSHRGB(in float3 SampleDirection, in float weight, in float MipLevel)
{
const float3 SampleColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, SampleDirection, MipLevel).rgb;
FThreeBandSHVector Sh3Vector = SHBasisFunction3(SampleDirection);
FThreeBandSHVectorRGB Result;
Result.R = MulSH3(Sh3Vector, SampleColor.r * weight);
Result.G = MulSH3(Sh3Vector, SampleColor.g * weight);
Result.B = MulSH3(Sh3Vector, SampleColor.b * weight);
return Result;
}
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
void ComputeSkyEnvMapDiffuseIrradianceCS(uint3 ThreadId : SV_DispatchThreadID)
{
const uint LinearIndex = THREADGROUP_SIZE_X * ThreadId.y + ThreadId.x;
#if 1
// For a 128x128 cubemap, sampling mip level 2 with only 8x8 samples matches closely the super sampled version.
const float3 SampleDirection = UniformSampleSphere((float2(ThreadId.xy)+0.5f) / float2(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y)).xyz;
IrradianceSHShared[LinearIndex] = SampleSHRGB(SampleDirection, UniformSampleSolidAngle, MipIndex);
#else
FThreeBandSHVectorRGB IrradianceSHAcc;
IrradianceSHAcc.R.V0 = IrradianceSHAcc.R.V1 = 0.0f; IrradianceSHAcc.R.V2 = 0.0f;
IrradianceSHAcc.G.V0 = IrradianceSHAcc.G.V1 = 0.0f; IrradianceSHAcc.G.V2 = 0.0f;
IrradianceSHAcc.B.V0 = IrradianceSHAcc.B.V1 = 0.0f; IrradianceSHAcc.B.V2 = 0.0f;
// Uniform super sampling.
// For a 128x128 cubemap, sampling mip level 0 with only 4x4 samples matches closely reference.
const uint MipLevel = 0;
const float SuperSampleAxisCount = 4.0f;
const float SuperSampleCount = SuperSampleAxisCount * SuperSampleAxisCount;
const float SuperSampleUniformSampleSolidAngle = UniformSampleSolidAngle / SuperSampleCount;
for (float U = 0.0f; U < 1.0f; U += 1.0f / SuperSampleAxisCount)
{
for (float V = 0.0f; V < 1.0f; V += 1.0f / SuperSampleAxisCount)
{
const float3 SampleDirection = UniformSampleSphere((float2(ThreadId.xy) + float2(U,V)) / float2(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y)).xyz;
IrradianceSHAcc = AddSH(IrradianceSHAcc, SampleSHRGB(SampleDirection, SuperSampleUniformSampleSolidAngle, MipLevel));
}
}
IrradianceSHShared[LinearIndex] = IrradianceSHAcc;
#endif
#if THREADGROUP_SIZE != 64
#error That is the only reduction supported today
#endif
// Wait for all group threads to be done
GroupMemoryBarrierWithGroupSync();
if (LinearIndex < 32)
{
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 32]);
}
GroupMemoryBarrierWithGroupSync();
if (LinearIndex < 16)
{
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 16]);
}
GroupMemoryBarrierWithGroupSync();
// The smallest wave size is 16 on Intel hardware. So now we can do simple math operations without group sync.
if (LinearIndex < 8)
{
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 8]);
}
if (LinearIndex < 4)
{
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 4]);
}
if (LinearIndex < 2)
{
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 2]);
}
if (LinearIndex < 1)
{
FThreeBandSHVectorRGB SkyIrradiance = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 1]);
// Pack the SH coefficients in a way that makes applying the lighting use the least shader instructions
// This has the diffuse convolution coefficients baked in. See "Stupid Spherical Harmonics (SH) Tricks".
// Also see UpdateSkyIrradianceGpuBuffer.
const float SqrtPI = sqrt(PI);
const float Coefficient0 = 1.0f / (2.0f * SqrtPI);
const float Coefficient1 = sqrt(3.0f) / (3.0f * SqrtPI);
const float Coefficient2 = sqrt(15.0f) / (8.0f * SqrtPI);
const float Coefficient3 = sqrt(5.0f) / (16.0f * SqrtPI);
const float Coefficient4 = 0.5f * Coefficient2;
OutIrradianceEnvMapSH[0].x = -Coefficient1 * SkyIrradiance.R.V0[3];
OutIrradianceEnvMapSH[0].y = -Coefficient1 * SkyIrradiance.R.V0[1];
OutIrradianceEnvMapSH[0].z = Coefficient1 * SkyIrradiance.R.V0[2];
OutIrradianceEnvMapSH[0].w = Coefficient0 * SkyIrradiance.R.V0[0] - Coefficient3 * SkyIrradiance.R.V1[2];//[6];
OutIrradianceEnvMapSH[1].x = -Coefficient1 * SkyIrradiance.G.V0[3];
OutIrradianceEnvMapSH[1].y = -Coefficient1 * SkyIrradiance.G.V0[1];
OutIrradianceEnvMapSH[1].z = Coefficient1 * SkyIrradiance.G.V0[2];
OutIrradianceEnvMapSH[1].w = Coefficient0 * SkyIrradiance.G.V0[0] - Coefficient3 * SkyIrradiance.G.V1[2];//[6];
OutIrradianceEnvMapSH[2].x = -Coefficient1 * SkyIrradiance.B.V0[3];
OutIrradianceEnvMapSH[2].y = -Coefficient1 * SkyIrradiance.B.V0[1];
OutIrradianceEnvMapSH[2].z = Coefficient1 * SkyIrradiance.B.V0[2];
OutIrradianceEnvMapSH[2].w = Coefficient0 * SkyIrradiance.B.V0[0] - Coefficient3 * SkyIrradiance.B.V1[2];//[6];
OutIrradianceEnvMapSH[3].x = Coefficient2 * SkyIrradiance.R.V1[0];//[4];
OutIrradianceEnvMapSH[3].y = -Coefficient2 * SkyIrradiance.R.V1[1];//V[5];
OutIrradianceEnvMapSH[3].z = 3.0f * Coefficient3 * SkyIrradiance.R.V1[2];//[6];
OutIrradianceEnvMapSH[3].w = -Coefficient2 * SkyIrradiance.R.V1[3];//[7];
OutIrradianceEnvMapSH[4].x = Coefficient2 * SkyIrradiance.G.V1[0];//[4];
OutIrradianceEnvMapSH[4].y = -Coefficient2 * SkyIrradiance.G.V1[1];//[5];
OutIrradianceEnvMapSH[4].z = 3.0f * Coefficient3 * SkyIrradiance.G.V1[2];//[6];
OutIrradianceEnvMapSH[4].w = -Coefficient2 * SkyIrradiance.G.V1[3];//[7];
OutIrradianceEnvMapSH[5].x = Coefficient2 * SkyIrradiance.B.V1[0];//[4];
OutIrradianceEnvMapSH[5].y = -Coefficient2 * SkyIrradiance.B.V1[1];//[5];
OutIrradianceEnvMapSH[5].z = 3.0f * Coefficient3 * SkyIrradiance.B.V1[2];//[6];
OutIrradianceEnvMapSH[5].w = -Coefficient2 * SkyIrradiance.B.V1[3];//[7];
OutIrradianceEnvMapSH[6].x = Coefficient4 * SkyIrradiance.R.V2;//[8];
OutIrradianceEnvMapSH[6].y = Coefficient4 * SkyIrradiance.G.V2;//[8];
OutIrradianceEnvMapSH[6].z = Coefficient4 * SkyIrradiance.B.V2;//[8];
OutIrradianceEnvMapSH[6].w = 1.0f;
// We inverse the weights applied onto the non directional SH component to recover the average sky irradiance.
const float3 DummyVector = float3(0.0, 0.0, 1.0);
const float SHBasisL0Weight = SHBasisFunction3(DummyVector).V0.x;
const float InvSHBand0Weights = 1.0f / (SHBasisL0Weight * 4.0f * PI);
const float SkyAverageIrradianceR = SkyIrradiance.R.V0.x * InvSHBand0Weights;
const float SkyAverageIrradianceG = SkyIrradiance.G.V0.x * InvSHBand0Weights;
const float SkyAverageIrradianceB = SkyIrradiance.B.V0.x * InvSHBand0Weights;
const float SkyAverageIrradiance = dot(float3(SkyAverageIrradianceR, SkyAverageIrradianceG, SkyAverageIrradianceB), .3333f);
OutIrradianceEnvMapSH[7].x = SkyAverageIrradiance;
OutIrradianceEnvMapSH[7].y = SkyAverageIrradiance;
OutIrradianceEnvMapSH[7].z = SkyAverageIrradiance;
OutIrradianceEnvMapSH[7].w = SkyAverageIrradiance;
}
}
#endif
#ifdef REALTIME_REFLECTION_HEIGHT_FOG
#include "HeightFogCommon.ush"
#if PERMUTATION_DEPTHTEXTURE
Texture2D DepthTexture;
#endif
void RenderRealTimeReflectionHeightFogVS(
in uint VertexId : SV_VertexID,
out float4 Position : SV_POSITION,
out float3 OutScreenVector : TEXCOORD0)
{
float2 UV = -1.0f;
UV = VertexId == 1 ? float2(-1.0f, 3.0f) : UV;
UV = VertexId == 2 ? float2(3.0f, -1.0f) : UV;
Position = float4(UV, 0.5f, 1.0f);
OutScreenVector = mul(float4(Position.xy, 1, 0), View.ScreenToTranslatedWorld).xyz;
}
void RenderRealTimeReflectionHeightFogPS(
in float4 SVPos : SV_POSITION,
in float3 ScreenVector : TEXCOORD0,
out float4 OutLuminance : SV_Target0
)
{
ResolvedView = ResolveView();
float4 WorldVector = mul(float4((SVPos.xy / 128.0f) * float2(2.0, -2.0) + float2(1.0, -1.0), 0.0, 0), ResolvedView.ScreenToTranslatedWorld);
#if PERMUTATION_DEPTHTEXTURE
float DeviceZ = DepthTexture.Load(int3(SVPos.xy, 0)).x;
const float HeightFogDistance = ConvertFromDeviceZ(DeviceZ);
#else
const float HeightFogDistance = 100000.0f * 10.0f; // 10 kilometers
#endif
float4 HeightFogInscatteringAndOpacity = CalculateHeightFog(normalize(ScreenVector)* HeightFogDistance);
const float OutputPreExposure = (ResolvedView.RealTimeReflectionCapture ? ResolvedView.RealTimeReflectionCapturePreExposure : ResolvedView.PreExposure);
HeightFogInscatteringAndOpacity.rgb *= OutputPreExposure;
OutLuminance = HeightFogInscatteringAndOpacity;
}
#endif