Files
UnrealEngine/Engine/Shaders/Private/MegaLights/MegaLights.usf
2025-05-18 13:04:45 +08:00

371 lines
12 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
// When loading SSS checkerboard pixel, do not adjust DiffuseColor/SpecularColor to preserve specular and diffuse lighting values for each pixel
#define ALLOW_SSS_MATERIAL_OVERRIDE 0
#include "../Common.ush"
#include "MegaLightsShading.ush"
groupshared uint SharedTileMode[THREADGROUP_SIZE * THREADGROUP_SIZE];
RWStructuredBuffer<uint> RWTileAllocator;
RWStructuredBuffer<uint> RWTileData;
uint TileDataStride;
uint DownsampledTileDataStride;
uint2 DownsampledViewMin;
uint2 DownsampledViewSize;
uint EnableTexturedRectLights;
uint DebugMode;
uint GetTileMode(uint InShading, uint InShadingRect, uint InShadingRectTextured)
{
uint Out;
Out = InShading;
if (SharedTileMode[0] & 0x20) // Rect light
{
if (SharedTileMode[0] & 0x40) // Rect light with texture
{
Out = InShadingRectTextured;
}
else
{
Out = InShadingRect;
}
}
return Out;
}
#ifdef TileClassificationCS
/**
* Run tile classification to generate tiles for each subsequent pass
*/
[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
void TileClassificationCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint LinearThreadIndex = GroupThreadId.x + THREADGROUP_SIZE * GroupThreadId.y;
SharedTileMode[LinearThreadIndex] = 0;
GroupMemoryBarrierWithGroupSync();
#if DOWNSAMPLED_CLASSIFICATION
uint2 ScreenCoord = DispatchThreadId.xy + DownsampledViewMin;
if (all(ScreenCoord < DownsampledViewMin + DownsampledViewSize))
#else
uint2 ScreenCoord = DispatchThreadId.xy + View.ViewRectMinAndSize.xy;
if (all(ScreenCoord < View.ViewRectMinAndSize.xy + View.ViewRectMinAndSize.zw))
#endif
{
#if DOWNSAMPLED_CLASSIFICATION
float2 ScreenUV = DownsampledScreenCoordToScreenUV(ScreenCoord);
uint2 EffectiveScreenCoord = DownsampledScreenCoordToScreenCoord(ScreenCoord);
#else
float2 ScreenUV = (ScreenCoord + 0.5f) * View.BufferSizeAndInvSize.zw;
uint2 EffectiveScreenCoord = ScreenCoord;
#endif
FMegaLightsMaterial Material = LoadMaterial(ScreenUV, EffectiveScreenCoord);
uint TileMode = 0;
if (!Material.IsValid())
{
TileMode = 0x1;
}
else if (Material.IsSimple())
{
TileMode = 0x2;
}
else if (Material.IsSingle())
{
TileMode = 0x4;
}
else if (Material.IsComplexSpecial())
{
TileMode = 0x10;
}
else // Complex
{
TileMode = 0x8;
}
const float SceneDepth = Material.Depth;
const uint EyeIndex = 0;
const uint GridIndex = ComputeLightGridCellIndex(EffectiveScreenCoord - View.ViewRectMin.xy, SceneDepth, EyeIndex);
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
if (CulledLightGridHeader.bHasRectLight)
{
TileMode |= 0x20;
}
if (CulledLightGridHeader.bHasTexturedLight && EnableTexturedRectLights != 0)
{
TileMode |= 0x40;
}
SharedTileMode[LinearThreadIndex] = TileMode;
}
GroupMemoryBarrierWithGroupSync();
// GroupShared reduction
if (LinearThreadIndex < 32)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 32];
}
GroupMemoryBarrierWithGroupSync();
if (LinearThreadIndex < 16)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 16];
}
GroupMemoryBarrierWithGroupSync();
if (LinearThreadIndex < 8)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 8];
}
GroupMemoryBarrierWithGroupSync();
if (LinearThreadIndex < 4)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 4];
}
GroupMemoryBarrierWithGroupSync();
if (LinearThreadIndex < 2)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 2];
}
GroupMemoryBarrierWithGroupSync();
if (LinearThreadIndex < 1)
{
SharedTileMode[LinearThreadIndex] = SharedTileMode[LinearThreadIndex] | SharedTileMode[LinearThreadIndex + 1];
}
if (LinearThreadIndex == 0)
{
#if DOWNSAMPLED_CLASSIFICATION
const uint DataStride = DownsampledTileDataStride;
#else
const uint DataStride = TileDataStride;
#endif
uint2 TileCoord = ScreenCoord / TILE_SIZE;
int TileMode = -1;
if (SharedTileMode[0] & 0x10) // ComplexSpecial
{
TileMode = GetTileMode(TILE_MODE_COMPLEX_SPECIAL_SHADING, TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT, TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT_TEXTURED);
}
else if (SharedTileMode[0] & 0x8) // Complex
{
TileMode = GetTileMode(TILE_MODE_COMPLEX_SHADING, TILE_MODE_COMPLEX_SHADING_RECT, TILE_MODE_COMPLEX_SHADING_RECT_TEXTURED);
}
else if (SharedTileMode[0] & 0x4) // Single
{
TileMode = GetTileMode(TILE_MODE_SINGLE_SHADING, TILE_MODE_SINGLE_SHADING_RECT, TILE_MODE_SINGLE_SHADING_RECT_TEXTURED);
}
else if (SharedTileMode[0] & 0x2) // Simple
{
TileMode = GetTileMode(TILE_MODE_SIMPLE_SHADING, TILE_MODE_SIMPLE_SHADING_RECT, TILE_MODE_SIMPLE_SHADING_RECT_TEXTURED);
}
else if (SharedTileMode[0] & 0x1)
{
TileMode = TILE_MODE_EMPTY;
}
if (TileMode >= 0)
{
uint MegaLightsTileIndex;
InterlockedAdd(RWTileAllocator[TileMode], 1, MegaLightsTileIndex);
RWTileData[DataStride * TileMode + MegaLightsTileIndex] = PackTile(TileCoord);
#if DEBUG_MODE && !DOWNSAMPLED_CLASSIFICATION
if (DebugMode == DEBUG_MODE_TILE_CLASSIFICATION)
{
FShaderPrintContext Ctx = InitShaderPrintContext(true, uint2(50, 50));
float4 Color = ColorWhite;
switch (TileMode)
{
case TILE_MODE_SIMPLE_SHADING :
case TILE_MODE_SIMPLE_SHADING_RECT :
case TILE_MODE_SIMPLE_SHADING_RECT_TEXTURED :
Color = ColorLightGreen; break;
case TILE_MODE_SINGLE_SHADING :
case TILE_MODE_SINGLE_SHADING_RECT :
case TILE_MODE_SINGLE_SHADING_RECT_TEXTURED :
Color = ColorYellow; break;
case TILE_MODE_COMPLEX_SHADING :
case TILE_MODE_COMPLEX_SHADING_RECT :
case TILE_MODE_COMPLEX_SHADING_RECT_TEXTURED:
Color = ColorLightRed; break;
case TILE_MODE_COMPLEX_SPECIAL_SHADING :
case TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT :
case TILE_MODE_COMPLEX_SPECIAL_SHADING_RECT_TEXTURED:
Color = ColorPurple; break;
case TILE_MODE_EMPTY :
case TILE_MODE_MAX :
Color = ColorSilver; break;
};
Color.a = 0.25f;
AddQuadSS(Ctx, TileCoord * TILE_SIZE, TileCoord * TILE_SIZE + TILE_SIZE, Color);
Color.a = 0.5f;
AddFilledQuadSS(Ctx, TileCoord * TILE_SIZE, TileCoord * TILE_SIZE + TILE_SIZE, Color);
}
#endif
}
}
}
#endif
RWBuffer<uint> RWTileIndirectArgs;
RWBuffer<uint> RWDownsampledTileIndirectArgs;
StructuredBuffer<uint> TileAllocator;
StructuredBuffer<uint> DownsampledTileAllocator;
#ifdef InitTileIndirectArgsCS
[numthreads(THREADGROUP_SIZE, 1, 1)]
void InitTileIndirectArgsCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint TileMode = DispatchThreadId.x;
if (TileMode < TILE_MODE_MAX)
{
WriteDispatchIndirectArgs(RWTileIndirectArgs, TileMode, TileAllocator[TileMode], 1, 1);
WriteDispatchIndirectArgs(RWDownsampledTileIndirectArgs, TileMode, DownsampledTileAllocator[TileMode], 1, 1);
}
}
#endif
#ifdef HairTransmittanceCS
#define VOXEL_TRAVERSAL_DEBUG 0
#define VOXEL_TRAVERSAL_TYPE VOXEL_TRAVERSAL_LINEAR_MIPMAP
#include "../BlueNoise.ush"
#include "MegaLightsRayTracing.ush"
#include "../HairStrands/HairStrandsDeepShadowCommon.ush"
#include "../HairStrands/HairStrandsCommon.ush"
#include "../HairStrands/HairStrandsDeepTransmittanceCommon.ush"
#include "../HairStrands/HairStrandsVisibilityCommon.ush"
#include "../HairStrands/HairStrandsVoxelPageCommon.ush"
#include "../HairStrands/HairStrandsVoxelPageTraversal.ush"
#if INPUT_TYPE != INPUT_TYPE_HAIRSTRANDS
#error INPUT_TYPE is required to be set to INPUT_TYPE_HAIRSTRANDS
#endif
uint2 NumSamplesPerPixel;
int2 SampleViewMin;
int2 SampleViewSize;
Texture2D<uint> LightSamples;
Texture2D<uint> LightSampleRays;
RWTexture2D<uint> RWTransmittanceMaskTexture;
#define USE_BLUE_NOISE 1
DEFINE_HAIR_BLUE_NOISE_JITTER_FUNCTION
float3 InternalGetHairVoxelJitter(uint2 PixelCoord, uint SampleIndex, uint MaxSampleCount, uint TimeIndex, uint JitterMode)
{
// Blue noise is cheaper to compute and h
float3 RandomSample = GetHairBlueNoiseJitter(PixelCoord, SampleIndex, MaxSampleCount, JitterMode > 1 ? 0 : TimeIndex).xyz;
return JitterMode > 0 ? RandomSample : float3(0,0,0);
}
/**
* Compute hair transmittance
*/
[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
void HairTransmittanceCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
const uint2 SampleCoord = DispatchThreadId.xy + SampleViewMin;
const uint2 DownsampledScreenCoord = uint2(SampleCoord.x >> NumSamplesPerPixelDivideShift.x, SampleCoord.y >> NumSamplesPerPixelDivideShift.y);
const uint2 ScreenCoord = DownsampledScreenCoordToScreenCoord(DownsampledScreenCoord);
const float2 ScreenUV = DownsampledScreenCoordToScreenUV(DownsampledScreenCoord);
if (all(SampleCoord < SampleViewMin + SampleViewSize))
{
const FMegaLightsMaterial Material = LoadMaterial(ScreenUV, ScreenCoord);
if (Material.bIsValid)
{
const uint2 PixelCoord = ScreenCoord;
const float2 UV = (PixelCoord.xy + float2(0.5f, 0.5f)) / float2(View.BufferSizeAndInvSize.xy);
const float PixelRadius = ConvertGivenDepthRadiusForProjectionType(VirtualVoxel.HairCoveragePixelRadiusAtDepth1, Material.Depth);
const float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, Material.Depth);
const FLightSample LightSample = UnpackLightSample(LightSamples[SampleCoord]);
const FLightSampleRay LightSampleRay = UnpackLightSampleRay(LightSampleRays[SampleCoord]);
const FLightSampleTrace LightSampleTrace = GetLightSampleTrace(TranslatedWorldPosition, LightSample.LocalLightIndex, LightSampleRay.UV);
// Early out when the ray is already occluded
if (LightSampleRay.bCompleted)
{
RWTransmittanceMaskTexture[SampleCoord] = 0;
return;
}
const float3 TranslatedLightPosition= TranslatedWorldPosition + LightSampleTrace.Direction * LightSampleTrace.Distance;
const float3 LightDirection = LightSampleTrace.Direction;
const FVirtualVoxelNodeDesc NodeDesc = UnpackVoxelNode(VirtualVoxel.NodeDescBuffer[Material.MacroGroupId], VirtualVoxel.PageResolution);
FVirtualVoxelCommonDesc CommonDesc;
CommonDesc.PageCountResolution = VirtualVoxel.PageCountResolution;
CommonDesc.PageTextureResolution= VirtualVoxel.PageTextureResolution;
CommonDesc.PageResolution = VirtualVoxel.PageResolution;
CommonDesc.PageResolutionLog2 = VirtualVoxel.PageResolutionLog2;
const uint SampleCount = 1;
const uint SampleIt = 0;
float3 SampleRandom = InternalGetHairVoxelJitter(PixelCoord, SampleIt, SampleCount, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
const float PositionBiasScale = 0.5f;
const float3 DepthBias = NodeDesc.VoxelWorldSize * (VirtualVoxel.DepthBiasScale_Transmittance * LightDirection + PositionBiasScale*(SampleRandom*2-1));
const float3 SampleTranslatedWorldPosition = TranslatedWorldPosition + DepthBias;
FHairTraversalSettings TraversalSettings = InitHairTraversalSettings();
TraversalSettings.DensityScale = VirtualVoxel.DensityScale_Transmittance;
TraversalSettings.CountThreshold = GetOpaqueVoxelValue();
TraversalSettings.DistanceThreshold = 100000;
TraversalSettings.bDebugEnabled = false;
TraversalSettings.SteppingScale = VirtualVoxel.SteppingScale_Transmittance;
TraversalSettings.Random = GetHairVoxelJitter(PixelCoord.xy, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
TraversalSettings.TanConeAngle = 0 /*TanLightAngle*/;
const FHairTraversalResult Result = ComputeHairCountVirtualVoxel(
SampleTranslatedWorldPosition,
TranslatedLightPosition,
CommonDesc,
NodeDesc,
VirtualVoxel.PageIndexBuffer,
VirtualVoxel.PageTexture,
TraversalSettings);
FHairTransmittanceMask Out;
Out.HairCount = Result.HairCount;
Out.Visibility = Result.Visibility;
RWTransmittanceMaskTexture[SampleCoord] = PackTransmittanceMask(Out);
}
}
}
#endif