You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
353 lines
12 KiB
Plaintext
353 lines
12 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "/Engine/Private/Common.ush"
|
|
|
|
#define STRATA_INLINE_SHADING 0
|
|
#define STRATA_SSS_MATERIAL_OVERRIDE 0
|
|
#include "/Engine/Private/Strata/Strata.ush"
|
|
|
|
#define TILE_SIZE 8
|
|
#define GROUP_THREAD_COUNT (TILE_SIZE*TILE_SIZE)
|
|
|
|
#if SHADER_CATEGORIZATION
|
|
|
|
uint MaxBytesPerPixel;
|
|
ByteAddressBuffer MaterialLobesBuffer;
|
|
|
|
// Note:
|
|
// This code is partial copy of PackStrataOut in Strata.ush.
|
|
// The command part will progressively be removed as we remove data from the gbuffer.
|
|
void ComputePostProcessBSDFData(
|
|
const FStrataPixelHeader Header,
|
|
const FStrataBSDF BSDF,
|
|
const FStrataAddressing StrataAddressing,
|
|
float3 V,
|
|
inout FStrataClassification Classification,
|
|
inout FStrataSubsurfaceData SSS,
|
|
inout FStrataTopLayerData TopLayer,
|
|
inout float TopLayerRoughness,
|
|
inout float TopLayerRoughnessAverageCount)
|
|
{
|
|
const float OpaqueBSDFThroughput = 0.0f;
|
|
const float FullThroughput = 1.0f;
|
|
const float FullyRough = 1.0f;
|
|
|
|
// FinalWeight does not always contains coverage (see Strata.ush)
|
|
const float BSDFWeightAvg = dot(BSDF.FinalWeight, 1.0f/3.0f);
|
|
|
|
// STRATA_TODO apply the same normal transform as for the material
|
|
float3x3 TangentBasis = StrataGetBSDFSharedBasis(Header, BSDF, StrataAddressing);
|
|
float3 N = TangentBasis[2];
|
|
//N = normalize(N);
|
|
|
|
|
|
BxDFContext ContextNoLight = (BxDFContext)0;
|
|
const float3 FakeL = float3(0, 0, 1);
|
|
Init(ContextNoLight, N, V, FakeL);
|
|
|
|
const bool bTopLayer = BSDF_GETISTOPLAYER(BSDF);
|
|
if (bTopLayer)
|
|
{
|
|
// We must take into account the weight in case horizontal blending is used,
|
|
// together with a threshold to avoid 0-length normal after normalization in case influence is fadeout using the Weight node.
|
|
TopLayer.WorldNormal += N * max(1e-5, BSDFWeightAvg);
|
|
}
|
|
|
|
Classification.ShadingModels |= StrataShadingModelBit(BSDF_GETTYPE(BSDF));
|
|
|
|
switch (BSDF_GETTYPE(BSDF))
|
|
{
|
|
case STRATA_BSDF_TYPE_SLAB:
|
|
{
|
|
Classification.bIsSimple = Classification.bIsSimple && IsStrataSlabFastPathCompatible(BSDF);
|
|
|
|
if (bTopLayer)
|
|
{
|
|
// Setup SSR for the top layer
|
|
TopLayerRoughness += BSDFWeightAvg * SLAB_ROUGHNESSX(BSDF);
|
|
TopLayerRoughnessAverageCount += BSDFWeightAvg;
|
|
}
|
|
|
|
// Select the latest encoutered SSS BSDF
|
|
if (!BSDF_GETISTHIN(BSDF) && // STRATA_TODO A material cannot have subsurface if using Thin mode. This is because DMFP does not match MFP at all (right now, SSS would just smears thin lighting model details out)
|
|
BSDF_GETHASSSS(BSDF) && BSDFWeightAvg > 0)
|
|
{
|
|
Classification.bHasSubsurface = true;
|
|
|
|
SSS.BaseColor = SLAB_DIFFUSEALBEDO(BSDF);
|
|
SSS.Specular = SLAB_F0(BSDF); // STRATA_TODO: Specular or F0?
|
|
|
|
// Profile ID: we only keep the latest ID, and profile will overtake any non-profile based SSS
|
|
SSS.bIsValid = true;
|
|
SSS.bIsProfile = SSS.bIsProfile || BSDF_GETHASSSSPROFILE(BSDF);
|
|
SSS.ProfileId = StrataSubsurfaceProfileIdTo8bits(SLAB_SSSPROFILEID(BSDF));
|
|
SSS.ProfileRadiusScale = SLAB_SSSPROFILERADIUSSCALE(BSDF);
|
|
|
|
// STRATA_TODO This should be accumulated according to the BSDF weight when we run this in the base pass.
|
|
// We cannot do that now because BSDFWeight contains weight*coverage*trhougput all mixed together.
|
|
SSS.DMFP = SLAB_SSSDMFP(BSDF);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STRATA_BSDF_TYPE_HAIR:
|
|
{
|
|
Classification.bIsSimple = false;
|
|
|
|
// No SSR
|
|
if (bTopLayer)
|
|
{
|
|
TopLayerRoughness += BSDFWeightAvg * FullyRough; // Do not trigger SSR by using fully rough
|
|
TopLayerRoughnessAverageCount += BSDFWeightAvg;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STRATA_BSDF_TYPE_SINGLELAYERWATER:
|
|
{
|
|
Classification.bIsSimple = false;
|
|
|
|
if (bTopLayer)
|
|
{
|
|
const float Roughness = SLW_ROUGHNESS(BSDF);
|
|
|
|
TopLayerRoughness += BSDFWeightAvg * Roughness;
|
|
TopLayerRoughnessAverageCount += BSDFWeightAvg;
|
|
}
|
|
break;
|
|
}
|
|
|
|
} // switch
|
|
}
|
|
|
|
void MainPS(
|
|
float4 SVPos : SV_POSITION,
|
|
out uint OutColor0 : SV_Target0,
|
|
out uint OutColor1 : SV_Target1,
|
|
out uint2 OutColor2 : SV_Target2)
|
|
{
|
|
const uint2 PixelPos = uint2(SVPos.xy);
|
|
|
|
FStrataClassification ClassificationData = (FStrataClassification)0;
|
|
FStrataSubsurfaceData SSSData = (FStrataSubsurfaceData)0;
|
|
FStrataTopLayerData TopLayerData = (FStrataTopLayerData)0;
|
|
|
|
FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), MaxBytesPerPixel);
|
|
FStrataPixelHeader Header = UnpackStrataHeaderIn(MaterialLobesBuffer, StrataAddressing);
|
|
|
|
ClassificationData.bIsStrataMaterial = Header.BSDFCount > 0;
|
|
ClassificationData.MaterialAO = 1.0;
|
|
ClassificationData.bIsSimple = true; // non strata material or sky pixels are considered as simple.
|
|
if (ClassificationData.bIsStrataMaterial)
|
|
{
|
|
float2 ScreenPosition = SvPositionToScreenPosition(SVPos).xy;
|
|
const float Depth = 1000000.0f;
|
|
float4 WorldPos = mul(float4(ScreenPosition * Depth, Depth, 1), View.ScreenToWorld);
|
|
const float3 V = normalize(View.WorldCameraOrigin - WorldPos.xyz);
|
|
|
|
ClassificationData.MaterialAO = Header.MaterialAO;
|
|
ClassificationData.bIsSimple = Header.BSDFCount == 1;
|
|
|
|
float TopLayerRoughness = 0.0f;
|
|
float TopLayerRoughnessAverageCount = 0.0f;
|
|
for (uint BSDFIndex = 0; BSDFIndex < Header.BSDFCount; ++BSDFIndex)
|
|
{
|
|
const FStrataBSDF BSDF = UnpackStrataBSDFIn(MaterialLobesBuffer, StrataAddressing);
|
|
ComputePostProcessBSDFData(Header, BSDF, StrataAddressing, V, ClassificationData, SSSData, TopLayerData, TopLayerRoughness, TopLayerRoughnessAverageCount);
|
|
}
|
|
|
|
TopLayerData.WorldNormal = normalize(TopLayerData.WorldNormal);
|
|
ClassificationData.TopLayerRoughness = TopLayerRoughnessAverageCount > 0.0f ? TopLayerRoughness / TopLayerRoughnessAverageCount : 0.0f;
|
|
}
|
|
else
|
|
{
|
|
TopLayerData.WorldNormal = normalize(float3(-1.0f, -1.0f, -1.0f));
|
|
}
|
|
|
|
OutColor0 = StrataPackClassificationData(ClassificationData);
|
|
OutColor1 = StrataPackTopLayerData(TopLayerData);
|
|
OutColor2 = StrataPackSSSData(SSSData);
|
|
}
|
|
#endif // SHADER_CATEGORIZATION
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
uint EncodeTile(uint2 TileCoord)
|
|
{
|
|
return TileCoord.x | (TileCoord.y << 16); // assumes 16bit is enough to represent a tiled resolution up to 65,535 :)
|
|
}
|
|
|
|
uint2 DecodeTile(uint In)
|
|
{
|
|
return uint2(In & 0xFFFF, In >> 16);
|
|
}
|
|
|
|
#if SHADER_TILE_CATEGORIZATION
|
|
int TileSize;
|
|
int bRectPrimitive;
|
|
int2 ViewResolution;
|
|
Texture2D<uint> ClassificationTexture;
|
|
RWBuffer<uint> SimpleTileIndirectDataBuffer;
|
|
RWBuffer<uint> SimpleTileListDataBuffer;
|
|
RWBuffer<uint> ComplexTileIndirectDataBuffer;
|
|
RWBuffer<uint> ComplexTileListDataBuffer;
|
|
|
|
groupshared uint s_IsComplexIsMaterialTile[GROUP_THREAD_COUNT];
|
|
|
|
[numthreads(TILE_SIZE, TILE_SIZE, 1)]
|
|
void TileMainCS(uint2 DispatchThreadId : SV_DispatchThreadID, uint LinearIndex : SV_GroupIndex, uint3 GroupId : SV_GroupID)
|
|
{
|
|
if (all(DispatchThreadId == 0))
|
|
{
|
|
SimpleTileIndirectDataBuffer[0] = bRectPrimitive > 0 ? 4 : 6;
|
|
ComplexTileIndirectDataBuffer[0] = bRectPrimitive > 0 ? 4 : 6;
|
|
}
|
|
|
|
// TODO: add a SM6 permutation with ballot?
|
|
const uint2 PixelCoord = DispatchThreadId;
|
|
|
|
// Pixels outside of the view area are considered simple to enable screen borders to receive the simple permutation when not aligned to shader group size.
|
|
bool bContainsComplexMaterial = false;
|
|
bool bContainsStrataMaterial = false;
|
|
if (all(PixelCoord < uint2(ViewResolution)))
|
|
{
|
|
const uint PackClassification = ClassificationTexture.Load(uint3(PixelCoord, 0));
|
|
FStrataClassification Data = StrataUnpackClassificationData(PackClassification);
|
|
bContainsComplexMaterial = !Data.bIsSimple;
|
|
bContainsStrataMaterial = Data.bIsStrataMaterial;
|
|
}
|
|
s_IsComplexIsMaterialTile[LinearIndex] = (bContainsComplexMaterial ? 1 : 0) | (bContainsStrataMaterial ? 2 : 0);
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 32)
|
|
{
|
|
s_IsComplexIsMaterialTile[LinearIndex] = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 32];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 16)
|
|
{
|
|
s_IsComplexIsMaterialTile[LinearIndex] = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 16];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
if (LinearIndex < 8)
|
|
{
|
|
s_IsComplexIsMaterialTile[LinearIndex] = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 8];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 4)
|
|
{
|
|
s_IsComplexIsMaterialTile[LinearIndex] = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 4];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
if (LinearIndex < 2)
|
|
{
|
|
s_IsComplexIsMaterialTile[LinearIndex] = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 2];
|
|
}
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
const uint FinalIsSimpleIsMaterialTile = s_IsComplexIsMaterialTile[LinearIndex] | s_IsComplexIsMaterialTile[LinearIndex + 1];
|
|
bContainsComplexMaterial = (FinalIsSimpleIsMaterialTile & 1) > 0;
|
|
bContainsStrataMaterial = (FinalIsSimpleIsMaterialTile & 2) > 0;
|
|
|
|
if (LinearIndex < 1 && bContainsStrataMaterial)
|
|
{
|
|
if (bContainsComplexMaterial)
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(ComplexTileIndirectDataBuffer[1], 1, WriteToIndex);
|
|
ComplexTileListDataBuffer[WriteToIndex] = EncodeTile(GroupId.xy);
|
|
}
|
|
else
|
|
{
|
|
uint WriteToIndex;
|
|
InterlockedAdd(SimpleTileIndirectDataBuffer[1], 1, WriteToIndex);
|
|
SimpleTileListDataBuffer[WriteToIndex] = EncodeTile(GroupId.xy);
|
|
}
|
|
}
|
|
}
|
|
#endif // SHADER_TILE_CATEGORIZATION
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_STENCIL_CATEGORIZATION
|
|
|
|
float4 OutputViewSizeAndInvSize;
|
|
float4 OutputBufferSizeAndInvSize;
|
|
float4x4 ViewScreenToTranslatedWorld;
|
|
Buffer<uint> TileListBuffer;
|
|
float4 DebugTileColor;
|
|
|
|
void StrataTilePassVS(
|
|
in uint InVertexId : SV_VertexID,
|
|
in uint InInstanceId : SV_InstanceID,
|
|
#if PERMUTATION_ENABLE_TEXCOORD_SCREENVECTOR
|
|
out float2 OutTexCoord : TEXCOORD0, // Used by DeferredLightPixelMain directional light
|
|
out float3 OutScreenVector : TEXCOORD1, // Used by DeferredLightPixelMain directional light
|
|
#endif
|
|
#if PERMUTATION_ENABLE_DEBUG
|
|
out uint2 OutTileCoord : TILE_COORD, // Used by StencilMainPS below
|
|
#endif
|
|
out float4 OutPosition : SV_POSITION) // Use by StencilMainPS
|
|
{
|
|
const uint2 TileCoord = DecodeTile(TileListBuffer[InInstanceId]);
|
|
|
|
uint2 TileVertex = TileCoord * TILE_SIZE;
|
|
TileVertex.x += InVertexId == 1 || InVertexId == 2 || InVertexId == 4 ? TILE_SIZE : 0;
|
|
TileVertex.y += InVertexId == 2 || InVertexId == 4 || InVertexId == 5 ? TILE_SIZE : 0;
|
|
|
|
OutPosition = float4(float2(TileVertex) * OutputViewSizeAndInvSize.zw * float2(2.0f, -2.0f) + float2(-1.0, 1.0f), 0.5f, 1.0f);
|
|
|
|
#if PERMUTATION_ENABLE_TEXCOORD_SCREENVECTOR
|
|
OutTexCoord = float2(TileVertex) * OutputBufferSizeAndInvSize.zw;
|
|
OutScreenVector = mul(float4(OutPosition.xy, 1, 0), ViewScreenToTranslatedWorld).xyz;
|
|
#endif
|
|
|
|
#if PERMUTATION_ENABLE_DEBUG
|
|
OutTileCoord = TileCoord;
|
|
#endif
|
|
}
|
|
|
|
void StencilMainPS(
|
|
in uint2 InTileCoord : TILE_COORD,
|
|
in float4 SVPos : SV_POSITION,
|
|
out float4 OutColor0 : SV_Target0)
|
|
{
|
|
const bool bTileX = (InTileCoord.x & 1) == 0;
|
|
const bool bTileY = (InTileCoord.y & 1) == 0;
|
|
const bool bChecker = (bTileX && bTileY) || (!bTileX && !bTileY);
|
|
OutColor0 = DebugTileColor * float4(1.0f, 1.0f, 1.0f, bChecker ? 0.33f : 0.66f);
|
|
OutColor0.rgb *= OutColor0.a; // premultiplied alpha blending assuming alpha is opacity==coverage
|
|
}
|
|
|
|
#endif //SHADER_STENCIL_CATEGORIZATION
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if SHADER_CLEAR_MATERIAL_BUFFER
|
|
|
|
RWByteAddressBuffer MaterialLobesBufferUAV;
|
|
uint MaxBytesPerPixel;
|
|
int2 TiledViewBufferResolution;
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void ClearMaterialBufferMainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
if (any(int2(DispatchThreadId.xy) > TiledViewBufferResolution))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Custom clear of the Strata material buffer.
|
|
// The first layer of tiled uints contains the header that we need to clear so we only write a single uint per pixel instead of clearing the entire buffer which would be too slow.
|
|
|
|
FStrataPixelHeader StrataHeader = InitialiseStrataPixelHeader();
|
|
uint BSDFCount = 0;
|
|
uint PackedStrataHeader = PackStrataHeaderIn(BSDFCount, StrataHeader);
|
|
|
|
FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(DispatchThreadId.xy, TiledViewBufferResolution, MaxBytesPerPixel);
|
|
MaterialLobesBufferUAV.Store(StrataAddressing.CurrentAddr, PackedStrataHeader);
|
|
}
|
|
|
|
#endif // SHADER_CLEAR_MATERIAL_BUFFER
|