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

582 lines
21 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../SceneTextureParameters.ush"
#include "../DeferredShadingCommon.ush"
#include "../ShadowFilteringCommon.ush"
#include "HairStrandsDeepShadowCommon.ush"
#include "HairStrandsCommon.ush"
#include "HairStrandsDeepTransmittanceCommon.ush"
#include "HairStrandsVisibilityCommon.ush"
#include "HairStrandsVoxelPageCommon.ush"
#define DEBUG_ENABLE 0
#if DEBUG_ENABLE
#include "../ShaderPrint.ush"
#endif //DEBUG_ENABLE
#ifndef MAX_HAIR_MACROGROUP_COUNT
#error MAX_HAIR_MACROGROUP_COUNT needs to be defined
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
// Utils function & structs
struct FTransmittanceSettings
{
int2 AtlasResolution;
float4x4 TranslatedWorldToLightTransform;
float4 AtlasScaleBias;
float3 LightDirection; // Direction from world position to the light
float3 TranslatedLightPosition;
bool bIsDirectional;
float DeepShadowDepthBiasScale;
float DeepShadowDensityScale;
float TransmittanceKernelApertureInDegree;
float3 Random;
uint DebugMode;
uint TransmittanceKernelType;
};
float3 GetViewVector(float3 InTranslatedWorldPosition)
{
float3 CameraToPixel = GetCameraVectorFromTranslatedWorldPosition(InTranslatedWorldPosition);
float3 V = -CameraToPixel;
return V;
}
float3 GetTranslatedWorldPosition(float2 UV, float SceneDepth)
{
const float2 ScreenPosition = (UV - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy;
return mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), View.ScreenToTranslatedWorld).xyz;
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Defines
// Need to match FDeepShadowData::MaxMacroGroupCount in HairRendering.h
#if SHADER_TRANSMITTANCE_DEEPSHADOW || SHADER_TRANSMITTANCE_VOXEL
#if PERMUTATION_GROUP_SIZE == 64
#define TRANSMITTANCE_GROUP_SIZE 64
#elif PERMUTATION_GROUP_SIZE == 32
#define TRANSMITTANCE_GROUP_SIZE 32
#else
#error Unknown group size
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////////////
// Deep shadow
#if SHADER_TRANSMITTANCE_DEEPSHADOW
StructuredBuffer<uint> DeepShadow_AtlasSlotIndexBuffer;
StructuredBuffer<FDeepShadowViewInfo> DeepShadow_ViewInfoBuffer;
uint2 DeepShadow_AtlasResolution;
uint LightChannelMask;
float4 ShadowChannelMask;
float4 TranslatedLightPosition_LightDirection;
float DeepShadow_DepthBiasScale;
float DeepShadow_DensityScale;
float LightRadius;
float DeepShadow_KernelAperture;
float4 DeepShadow_LayerDepths;
uint DeepShadow_KernelType;
uint DeepShadow_DebugMode;
Texture2D<float> DeepShadow_FrontDepthTexture;
Texture2D<float4> DeepShadow_DomTexture;
Buffer<uint4> IndirectArgsBuffer;
RWBuffer<uint> OutTransmittanceMask;
FHairTransmittanceMask ComputeTransmittance(
float3 TranslatedWorldPosition,
FTransmittanceSettings Settings,
float4 InLayerDepths,
Texture2D<float> FrontDepthTexture,
Texture2D<float4> DomTexture)
{
FHairTransmittanceMask Out = InitHairTransmittanceMask();
{
// LightSpacePosition is 'TranslatedWorldPosition' in LightSpace (TexelCoord.XY / NDC Depth.Z)
const float3 LightSpacePosition = ToLightPosition(TranslatedWorldPosition, Settings.TranslatedWorldToLightTransform) * float3(Settings.AtlasScaleBias.xy, 1) + float3(Settings.AtlasScaleBias.zw, 0);
float DepthBias = 0;
if (Settings.DeepShadowDepthBiasScale > 0)
{
#if 0
const float DephtBiasSlope = 6;
const float DefaultDepthBias = LAYER_DEPTH0 * Settings.DeepShadowDepthBiasScale;
DepthBias = (CosLightAngle*DephtBiasSlope + 1) * DefaultDepthBias;
#else
DepthBias = InLayerDepths[0] * Settings.DeepShadowDepthBiasScale;
#endif
}
// Compute the number of hair count between light & shading point
if (Settings.TransmittanceKernelType == 4)
{
//Out = SampleDOM_PCF_Accurate(LightSpacePosition.xyz, DepthBias, InLayerDepths, FrontDepthTexture, DomTexture, GBuffer, SinLightAngle, HairLUTTexture);
Out.HairCount = 0;
Out.Visibility = 1;
}
else
{
float HairCount = 0;
if (Settings.TransmittanceKernelType == 3)
{
HairCount = SampleDOM_PCSS(LightSpacePosition.xyz, Settings.AtlasResolution, DepthBias, InLayerDepths, FrontDepthTexture, DomTexture, Settings.TransmittanceKernelApertureInDegree, Settings.Random.xy);
}
else if (Settings.TransmittanceKernelType == 2)
{
HairCount = SampleDOM_PCF(LightSpacePosition.xyz, DepthBias, InLayerDepths, FrontDepthTexture, DomTexture);
}
else if (Settings.TransmittanceKernelType == 1)
{
HairCount = SampleDOM_PCF2x2(LightSpacePosition.xyz, DepthBias, InLayerDepths, FrontDepthTexture, DomTexture);
}
else
{
HairCount = 0;
}
Out.HairCount = HairCount * Settings.DeepShadowDensityScale;
Out.Visibility = 1;
}
if (Settings.DebugMode != 0)
{
Out.HairCount = 1;
}
}
return Out;
}
[numthreads(TRANSMITTANCE_GROUP_SIZE, 1, 1)]
void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
{
// Note: Use a fixed group count width (HAIR_VISIBILITY_GROUP_COUNT_WIDTH) for avoiding loading the indirect args (to avoid dep. memory fetch)
const uint SampleIndex = DispatchThreadId.x + DispatchThreadId.y * TRANSMITTANCE_GROUP_SIZE * HAIR_VISIBILITY_GROUP_COUNT_WIDTH;
const uint MaxVisibilityNodeCount = HairStrands.HairSampleCount[0];
if (SampleIndex >= MaxVisibilityNodeCount)
{
return;
}
const uint2 PixelCoord = HairStrands.HairSampleCoords[SampleIndex];
const float2 UV = (PixelCoord + float2(0.5f, 0.5f)) / float2(View.BufferSizeAndInvSize.xy);
const float3 TransmittanceRandom = float3(InterleavedGradientNoise(PixelCoord, 1), InterleavedGradientNoise(PixelCoord, 2), InterleavedGradientNoise(PixelCoord, 3));
{
const FHairSample Sample = UnpackHairSample(HairStrands.HairSampleData[SampleIndex]);
if ((LightChannelMask & Sample.LightChannelMask) == 0)
{
OutTransmittanceMask[SampleIndex] = InitNullPackedHairTransmittanceMask();
return;
}
const uint MacroGroupIndex = clamp(Sample.MacroGroupId, 0, MAX_HAIR_MACROGROUP_COUNT - 1);
const uint AtlasSlotIndex = DeepShadow_AtlasSlotIndexBuffer[MacroGroupIndex];
const FDeepShadowViewInfo ShadowViewInfo = DeepShadow_ViewInfoBuffer[AtlasSlotIndex];
const float4x4 TranslatedWorldToLightTransform = ShadowViewInfo.TranslatedWorldToClip;
const float4 AtlasScaleBias = ShadowViewInfo.AtlasScaleBias * float4(DeepShadow_AtlasResolution, DeepShadow_AtlasResolution);
const float SceneDepth = ConvertFromDeviceZ(Sample.Depth);
const float3 TranslatedWorldPosition = GetTranslatedWorldPosition(UV, SceneDepth);
FTransmittanceSettings Settings;
Settings.AtlasResolution = DeepShadow_AtlasResolution;
Settings.TranslatedWorldToLightTransform = TranslatedWorldToLightTransform;
Settings.AtlasScaleBias = AtlasScaleBias;
Settings.bIsDirectional = IsLightDirectional(TranslatedLightPosition_LightDirection);
Settings.LightDirection = GetTranslatedLightDirection(TranslatedLightPosition_LightDirection, TranslatedWorldPosition);
Settings.TranslatedLightPosition = GetTranslatedLightPosition(TranslatedLightPosition_LightDirection, TranslatedWorldPosition);
Settings.DeepShadowDepthBiasScale = DeepShadow_DepthBiasScale;
Settings.DeepShadowDensityScale = DeepShadow_DensityScale;
Settings.TransmittanceKernelApertureInDegree = DeepShadow_KernelAperture;
Settings.TransmittanceKernelType = DeepShadow_KernelType;
Settings.Random = TransmittanceRandom;
Settings.DebugMode = DeepShadow_DebugMode;
const FHairTransmittanceMask TransmittanceMask = ComputeTransmittance(TranslatedWorldPosition, Settings, DeepShadow_LayerDepths, DeepShadow_FrontDepthTexture, DeepShadow_DomTexture);
OutTransmittanceMask[SampleIndex] = PackTransmittanceMask(TransmittanceMask);
}
}
#endif // #if SHADER_TRANSMITTANCE_DEEPSHADOW
////////////////////////////////////////////////////////////////////////////////////////////////
// Voxel volume
#if SHADER_TRANSMITTANCE_VOXEL
#if PERMUTATION_TRAVERSAL == 1
#define VOXEL_TRAVERSAL_TYPE VOXEL_TRAVERSAL_LINEAR_MIPMAP
#else
#define VOXEL_TRAVERSAL_TYPE VOXEL_TRAVERSAL_LINEAR
#endif
#define VOXEL_TRAVERSAL_DEBUG 0
#include "HairStrandsVoxelPageTraversal.ush"
#include "../LightGridCommon.ush"
#if VOXEL_TRAVERSAL_DEBUG
#include "../ShaderPrint.ush"
void PrintInfo(uint Index, uint2 PixelCoord, FHairTransmittanceMask TransmittanceMask)
{
#if 0
const uint2 OutputResolution = uint2(1024, 1024);
float2 Origin = (PixelCoord) / float2(OutputResolution);
Origin.y += (Index % 8) * 2 * ShaderPrintUniform.FontSize.w;
FShaderPrintContext Context = InitShaderPrintContext(true, Origin);
Print(Context, TEXT("Hair Count "));
Print(Context, TransmittanceMask.HairCount);
Newline(Context);
Print(Context, TEXT("Visibility "));
Print(Context, TransmittanceMask.Visibility);
Newline(Context);
#endif
}
#endif // VOXEL_TRAVERSAL_DEBUG
uint LightChannelMask;
float4 TranslatedLightPosition_LightDirection;
float LightRadius;
#if PERMUTATION_ONE_PASS
Texture2D<uint4> ShadowMaskBitsTexture;
#else
Texture2D<float4> RayMarchMaskTexture;
float4 ShadowChannelMask;
#endif
Buffer<uint> IndirectArgsBuffer;
RWBuffer<uint> OutTransmittanceMask;
#include "../VirtualShadowMaps/VirtualShadowMapLightGrid.ush"
#define USE_BLUE_NOISE 1
#include "../BlueNoise.ush"
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
#if USE_BLUE_NOISE
float3 RandomSample = GetHairBlueNoiseJitter(PixelCoord, SampleIndex, MaxSampleCount, JitterMode > 1 ? 0 : TimeIndex).xyz;
#else
float3 RandomSample = GetHairVoxelJitter(PixelCoord, View.StateFrameIndexMod8, JitterMode);
#endif
return JitterMode > 0 ? RandomSample : float3(0,0,0);
}
#include "../SSRT/SSRTRayCast.ush"
#include "../HZB.ush"
uint bUseScreenTrace;
float ScreenTraceLength;
// TODO: Merge with the version in HairStrandsEnvironementLighting.usf
float GetRayVisibility(float3 TranslatedWorldPosition,float SceneDepth, float3 RayDirection, uint2 PixelCoord, uint PixelRayIndex, uint NumPixelSamples)
{
const float SlopeCompareToleranceScale = 0.5f;
const float MaxScreenTraceFraction = ScreenTraceLength * 2.0f / (float)View.ViewSizeAndInvSize.x;
float TraceDistance = MaxScreenTraceFraction * 2.0 * GetScreenRayLengthMultiplierForProjectionType(SceneDepth).x;
float DepthThresholdScale = View.ProjectionDepthThicknessScale;
const float PositionBias = 0.1f;
const float3 TranslatedWorldStartPosition = TranslatedWorldPosition + RayDirection * PositionBias;
FSSRTCastingSettings CastSettings = CreateDefaultCastSettings();
CastSettings.bStopWhenUncertain = true;
bool bHit = false;
float Level;
float3 HitUVz;
bool bRayWasClipped;
uint NumSteps = 4;
float StartMipLevel = 0;
float RayRoughness = .2f;
uint2 NoiseCoord = PixelCoord * uint2(NumPixelSamples, 1) + uint2(PixelRayIndex, 0);
float StepOffset = VirtualVoxel.JitterMode > 0 ? BlueNoiseScalar(PixelCoord, View.StateFrameIndex) : 0;
FSSRTRay Ray = InitScreenSpaceRayFromWorldSpace(
TranslatedWorldStartPosition, RayDirection,
/* WorldTMax = */ TraceDistance,
/* SceneDepth = */ SceneDepth,
/* SlopeCompareToleranceScale */ SlopeCompareToleranceScale * DepthThresholdScale * (float)NumSteps,
/* bExtendRayToScreenBorder = */ false,
/* out */ bRayWasClipped);
bool bUncertain;
float3 DebugOutput;
CastScreenSpaceRay(
ClosestHZBTexture, ClosestHZBTextureSampler,
StartMipLevel,
CastSettings,
Ray, RayRoughness, NumSteps, StepOffset - .9f,
HZBUvFactorAndInvFactor, false,
/* out */ DebugOutput,
/* out */ HitUVz,
/* out */ Level,
/* out */ bHit,
/* out */ bUncertain);
bHit = bHit && !bUncertain;
return bHit ? 0.0f : 1.0f;
}
FHairTransmittanceMask ComputeTransmittanceVoxel(
const uint2 PixelCoord,
const float PixelRadius,
const float SceneDepth,
float3 TranslatedWorldPosition,
uint MacroGroupId,
FTransmittanceSettings Settings,
bool bDebugEnabled)
{
// Cone opening - Area light transmission is disabled as it is too noisy for now
const float TanLightAngle = 0; // Settings.bIsDirectional ? 0 : LightRadius / length(Settings.TranslatedLightPosition - TranslatedWorldPosition);
const FVirtualVoxelNodeDesc NodeDesc = UnpackVoxelNode(VirtualVoxel.NodeDescBuffer[MacroGroupId], VirtualVoxel.PageResolution);
FVirtualVoxelCommonDesc CommonDesc;
CommonDesc.PageCountResolution = VirtualVoxel.PageCountResolution;
CommonDesc.PageTextureResolution= VirtualVoxel.PageTextureResolution;
CommonDesc.PageResolution = VirtualVoxel.PageResolution;
CommonDesc.PageResolutionLog2 = VirtualVoxel.PageResolutionLog2;
// Compute the number of hair count between light & shading point
const float DistanceThreshold = 100000;
float AvgHairCount = 0;
float AvgHairVisility = 0;
#if PERMUTATION_SUPERSAMPLING
const uint SampleCount = 8;
for (uint SampleIt = 0; SampleIt < SampleCount; ++SampleIt)
#else
const uint SampleCount = 1;
const uint SampleIt = 0;
#endif
{
float3 SampleRandom = InternalGetHairVoxelJitter(PixelCoord, SampleIt, SampleCount, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
const float PositionBiasScale = 0.5f;
const float3 DepthBias = NodeDesc.VoxelWorldSize * (VirtualVoxel.DepthBiasScale_Transmittance * Settings.LightDirection + PositionBiasScale*(SampleRandom*2-1));
const float3 SampleTranslatedWorldPosition = TranslatedWorldPosition + DepthBias;
FHairTraversalSettings TraversalSettings = InitHairTraversalSettings();
TraversalSettings.DensityScale = VirtualVoxel.DensityScale_Transmittance;
TraversalSettings.CountThreshold = GetOpaqueVoxelValue();
TraversalSettings.DistanceThreshold = DistanceThreshold;
TraversalSettings.bDebugEnabled = bDebugEnabled;
TraversalSettings.SteppingScale = VirtualVoxel.SteppingScale_Transmittance;
TraversalSettings.Random = SampleRandom;
TraversalSettings.TanConeAngle = TanLightAngle;
TraversalSettings.PixelRadius = PixelRadius;
const FHairTraversalResult Result = ComputeHairCountVirtualVoxel(
SampleTranslatedWorldPosition,
Settings.TranslatedLightPosition,
CommonDesc,
NodeDesc,
VirtualVoxel.PageIndexBuffer,
VirtualVoxel.PageTexture,
TraversalSettings);
InitHairTraversalResult();
if (bUseScreenTrace)
{
const float HairCountPerScreenSpaceIntersection = 1.5f; // Arbitrary value, visually tweaked
const float ScreenTraceVis = GetRayVisibility(TranslatedWorldPosition, SceneDepth, Settings.LightDirection, PixelCoord, SampleIt, SampleCount);
AvgHairCount += saturate(1.f-ScreenTraceVis) * HairCountPerScreenSpaceIntersection;
}
AvgHairCount += Result.HairCount;
AvgHairVisility += Result.Visibility;
}
#if PERMUTATION_SUPERSAMPLING
AvgHairCount /= max(1u, SampleCount);
AvgHairVisility /= max(1u, SampleCount);
#endif
FHairTransmittanceMask Out;
Out.HairCount = AvgHairCount;
Out.Visibility = AvgHairVisility;
return Out;
}
[numthreads(TRANSMITTANCE_GROUP_SIZE, 1, 1)]
void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
#if PERMUTATION_ONE_PASS
{
const uint SampleIndex = DispatchThreadId.x + DispatchThreadId.y * TRANSMITTANCE_GROUP_SIZE * HAIR_VISIBILITY_GROUP_COUNT_WIDTH;
const uint MaxVisibilityNodeCount = HairStrands.HairSampleCount[0];
if (SampleIndex >= MaxVisibilityNodeCount)
{
return;
}
const FHairSample Sample = UnpackHairSample(HairStrands.HairSampleData[SampleIndex]);
const uint MacroGroupIndex = clamp(Sample.MacroGroupId, 0, MAX_HAIR_MACROGROUP_COUNT - 1);
const float SceneDepth = ConvertFromDeviceZ(Sample.Depth);
const uint2 PixelCoord = HairStrands.HairSampleCoords[SampleIndex];
const float2 UV = (PixelCoord.xy + float2(0.5f, 0.5f)) / float2(View.BufferSizeAndInvSize.xy);
const float PixelRadius = ConvertGivenDepthRadiusForProjectionType(VirtualVoxel.HairCoveragePixelRadiusAtDepth1, SceneDepth);
float3 TranslatedWorldPosition = GetTranslatedWorldPosition(UV, SceneDepth);
if (View.StereoPassIndex == 1)
{
TranslatedWorldPosition += VirtualVoxel.TranslatedWorldOffsetStereoCorrection;
}
const uint4 PackedShadowMask = ShadowMaskBitsTexture[PixelCoord];
const float3 Random = GetHairVoxelJitter(PixelCoord.xy, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
const uint2 LocalPixelPos = PixelCoord;
// Use VSM light grid index remapping to ensure we compute transmittance value only for shadowed light
// The logic to compute light index needs to be identical as in DeferredLightPixelShader.usf / ClusteredDeferredShadingPixelShader.usf
const FCulledLightsGridHeader CulledLightGridHeader = VirtualShadowMapGetLightsGridHeader(LocalPixelPos, SceneDepth);
const uint LightCount = min(GetPackedShadowMaskMaxLightCount(), CulledLightGridHeader.NumLights);
LOOP
for (uint LightIndex = 0; LightIndex < LightCount; ++LightIndex)
{
const uint OutputIndex = SampleIndex + MaxVisibilityNodeCount * LightIndex;
// The Virtual Shadow Remap stores directional lights first
const FLocalLightData LightData = VirtualShadowMapGetLocalLightData(CulledLightGridHeader, LightIndex);
const float3 TranslatedLightPosition = UnpackLightTranslatedWorldPosition(LightData);
// Early out when the shadow mask bits are zero
if (UnpackShadowMask(PackedShadowMask, LightIndex) == 0)
{
OutTransmittanceMask[OutputIndex] = PackTransmittanceMask(InitHairTransmittanceMask());
continue;
}
// Early out when mismatching light channel
if ((Sample.LightChannelMask & UnpackLightingChannelMask(LightData)) == 0)
{
OutTransmittanceMask[OutputIndex] = InitNullPackedHairTransmittanceMask();
continue;
}
FTransmittanceSettings Settings;
Settings.bIsDirectional = false;
Settings.LightDirection = normalize(TranslatedLightPosition - TranslatedWorldPosition);
Settings.TranslatedLightPosition = TranslatedLightPosition;
Settings.DeepShadowDensityScale = 0; // Use virtual voxel struct value
Settings.DeepShadowDepthBiasScale = 0; // Use virtual voxel struct value
Settings.Random = Random;
#if DEBUG_ENABLE
const bool bDebugEnabled = PixelCoord.x == GetCursorPos().x && PixelCoord.y == GetCursorPos().y;
#else
const bool bDebugEnabled = false;
#endif
const FHairTransmittanceMask Out = ComputeTransmittanceVoxel(
PixelCoord,
PixelRadius,
SceneDepth,
TranslatedWorldPosition,
MacroGroupIndex,
Settings,
bDebugEnabled);
OutTransmittanceMask[OutputIndex] = PackTransmittanceMask(Out);
}
}
#else // PERMUTATION_ONE_PASS
{
const uint SampleIndex = DispatchThreadId.x + DispatchThreadId.y * TRANSMITTANCE_GROUP_SIZE * HAIR_VISIBILITY_GROUP_COUNT_WIDTH;
const uint MaxVisibilityNodeCount = HairStrands.HairSampleCount[0];
if (SampleIndex >= MaxVisibilityNodeCount)
{
return;
}
const uint2 PixelCoord = HairStrands.HairSampleCoords[SampleIndex];
if (dot(RayMarchMaskTexture.Load(uint3(PixelCoord, 0)), ShadowChannelMask) == 0)
{
// This pixel is already fully shadowed opaque. (RayMarchMaskTexture is computed using the closest sample as of today)
OutTransmittanceMask[SampleIndex] = InitNullPackedHairTransmittanceMask();
return;
}
#if VOXEL_TRAVERSAL_DEBUG
const bool bDebugEnabled = PixelCoord.x == GetCursorPos().x && PixelCoord.y == GetCursorPos().y;
#else
const bool bDebugEnabled = false;
#endif
const float2 UV = (PixelCoord.xy + float2(0.5f, 0.5f)) / float2(View.BufferSizeAndInvSize.xy);
{
const FHairSample Sample = UnpackHairSample(HairStrands.HairSampleData[SampleIndex]);
if ((LightChannelMask & Sample.LightChannelMask) == 0)
{
OutTransmittanceMask[SampleIndex] = InitNullPackedHairTransmittanceMask();
return;
}
const float SceneDepth = ConvertFromDeviceZ(Sample.Depth);
float3 TranslatedWorldPosition = GetTranslatedWorldPosition(UV, SceneDepth);
if (View.StereoPassIndex == 1)
{
TranslatedWorldPosition += VirtualVoxel.TranslatedWorldOffsetStereoCorrection;
}
const uint MacroGroupIndex = clamp(Sample.MacroGroupId, 0, MAX_HAIR_MACROGROUP_COUNT - 1);
FTransmittanceSettings Settings;
Settings.bIsDirectional = IsLightDirectional(TranslatedLightPosition_LightDirection);
Settings.LightDirection = GetTranslatedLightDirection(TranslatedLightPosition_LightDirection, TranslatedWorldPosition);
Settings.TranslatedLightPosition = GetTranslatedLightPosition(TranslatedLightPosition_LightDirection, TranslatedWorldPosition);
Settings.DeepShadowDensityScale = 0; // Use virtual voxel struct value
Settings.DeepShadowDepthBiasScale = 0; // Use virtual voxel struct value
Settings.Random = GetHairVoxelJitter(PixelCoord.xy, View.StateFrameIndexMod8, VirtualVoxel.JitterMode);
const float PixelRadius = ConvertGivenDepthRadiusForProjectionType(VirtualVoxel.HairCoveragePixelRadiusAtDepth1, SceneDepth);
const FHairTransmittanceMask Out = ComputeTransmittanceVoxel(PixelCoord, PixelRadius, SceneDepth, TranslatedWorldPosition, MacroGroupIndex, Settings, bDebugEnabled);
#if VOXEL_TRAVERSAL_DEBUG
if (bDebugEnabled)
{
PrintInfo(SampleIndex, PixelCoord, Out);
}
#endif
OutTransmittanceMask[SampleIndex] = PackTransmittanceMask(Out);
}
}
#endif // PERMUTATION_ONE_PASS
#endif // SHADER_TRANSMITTANCE_VOXEL
////////////////////////////////////////////////////////////////////////////////////////////////
#if SHADER_CLEAR
uint ElementCount;
RWBuffer<uint> OutputMask;
[numthreads(64, 1, 1)]
void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
{
const uint Index = DispatchThreadId.x;
if (Index >= ElementCount)
{
return;
}
OutputMask[Index] = PackTransmittanceMask(InitHairTransmittanceMask());
}
#endif // SHADER_CLEAR