study/first_study/Library/PackageCache/com.unity.render-pipelines.universal@d10049dfa479/Runtime/RendererFeatures/SurfaceCacheGI/PatchAllocation.compute
jh04010421 739d49f1a0 Unity | 2026.01.20
수업 실습 파일
2026-01-20 11:01:57 +09:00

228 lines
10 KiB
Plaintext

#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal glcore ps5
#pragma kernel Allocate
#define PATCH_UTIL_USE_RW_IRRADIANCE_BUFFER
#define PATCH_UTIL_USE_RW_CELL_INDEX_BUFFER
#define PATCH_UTIL_USE_RW_CELL_ALLOCATION_MARK_BUFFER
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Sampling/Hashes.hlsl"
#include "SurfaceCacheCore/VectorLogic.hlsl"
#include "SurfaceCacheCore/IrradianceCompression.hlsl"
#include "SurfaceCacheCore/PatchUtil.hlsl"
RWStructuredBuffer<uint> _RingConfigBuffer;
RWStructuredBuffer<PatchUtil::PatchGeometry> _PatchGeometries;
RWStructuredBuffer<uint> _PatchCellIndices;
RWStructuredBuffer<PatchUtil::PatchCounterSet> _PatchCounterSets;
RWStructuredBuffer<SphericalHarmonics::RGBL1> _PatchIrradiances0;
RWStructuredBuffer<SphericalHarmonics::RGBL1> _PatchIrradiances1;
RWStructuredBuffer<uint> _CellAllocationMarks;
RWStructuredBuffer<uint> _CellPatchIndices;
StructuredBuffer<int3> _CascadeOffsets;
Texture2D<float> _CurrentFullResScreenDepths;
Texture2D<float3> _CurrentFullResScreenFlatNormals;
Texture2D<float2> _CurrentFullResScreenMotionVectors;
Texture2D<float3> _PreviousLowResScreenIrradiancesL0;
Texture2D<float3> _PreviousLowResScreenIrradiancesL10;
Texture2D<float3> _PreviousLowResScreenIrradiancesL11;
Texture2D<float3> _PreviousLowResScreenIrradiancesL12;
Texture2D<float> _PreviousLowResScreenNdcDepths;
uint _FrameIdx;
uint _GridSize;
float _VoxelMinSize;
uint _CascadeCount;
uint _RingConfigOffset;
float4x4 _CurrentClipToWorldTransform;
float4x4 _PreviousClipToWorldTransform;
float3 _GridTargetPos;
uint2 _LowResScreenSize;
uint2 _FullResPixelOffset;
int _UseMotionVectorSeeding;
uint CountLeadingZeroes(uint x)
{
// Note that this assumes firstbithigh(0) = -1.
return 31 - firstbithigh(x);
}
// https://andrew-helmer.github.io/permute/
// https://graphics.pixar.com/library/MultiJitteredSampling/
uint RandomPermute(uint idx, uint len, uint seed)
{
const uint mask = 0xFFFFFFFF >> CountLeadingZeroes(len - 1);
// This max guard is required and it is not clear why.
// https://jira.unity3d.com/browse/GFXLIGHT-1616
const uint iterMax = 16;
uint iterCount = 0;
do {
idx ^= seed;
idx *= 0xe170893d;
idx ^= seed >> 16;
idx ^= (idx & mask) >> 4;
idx ^= seed >> 8;
idx *= 0x0929eb3f;
idx ^= seed >> 23;
idx ^= (idx & mask) >> 1;
idx *= 1 | seed >> 27;
idx *= 0x6935fa69;
idx ^= (idx & mask) >> 11;
idx *= 0x74dcb303;
idx ^= (idx & mask) >> 2;
idx *= 0x9e501cc3;
idx ^= (idx & mask) >> 2;
idx *= 0xc860a3df;
idx &= mask;
idx ^= idx >> 5;
iterCount++;
} while (idx >= len && iterCount < iterMax);
return idx;
}
#define GROUP_SIZE 8
[numthreads(GROUP_SIZE, GROUP_SIZE, 1)]
void Allocate(uint2 lowResPixelPos : SV_DispatchThreadID)
{
if (any(lowResPixelPos >= _LowResScreenSize))
return;
const uint lowResThreadPosIndex = lowResPixelPos.y * _LowResScreenSize.x + lowResPixelPos.x;
const uint shuffleHash = LowBiasHash32(_FrameIdx, 1); // We pass a seed of 1 to avoid the degenerate zero case.
const uint shuffledLowResThreadPosIndex = RandomPermute(lowResThreadPosIndex, _LowResScreenSize.x * _LowResScreenSize.y, shuffleHash);
lowResPixelPos = uint2(shuffledLowResThreadPosIndex % _LowResScreenSize.x, shuffledLowResThreadPosIndex / _LowResScreenSize.x);
const uint2 fullResPixelPos = lowResPixelPos * lowResScreenScaling + _FullResPixelOffset;
uint2 fullResScreenSize;
_CurrentFullResScreenDepths.GetDimensions(fullResScreenSize.x, fullResScreenSize.y);
if (any(fullResPixelPos >= fullResScreenSize))
return;
const float ndcDepth = LoadNdcDepth(_CurrentFullResScreenDepths, fullResPixelPos);
if (ndcDepth == invalidNdcDepth)
return;
const float2 rcpFullResScreenSize = rcp(float2(fullResScreenSize));
const float2 sourceUvPos = PixelPosToUvPos(fullResPixelPos, rcpFullResScreenSize);
const float3 sourceWorldPosition = ComputeWorldSpacePosition(sourceUvPos, ndcDepth, _CurrentClipToWorldTransform);
const float3 sourceWorldFlatNormal = _CurrentFullResScreenFlatNormals[fullResPixelPos];
PatchUtil::VolumePositionResolution patchPosResolution = PatchUtil::ResolveVolumePosition(sourceWorldPosition, _GridTargetPos, _GridSize, _CascadeOffsets, _CascadeCount, _VoxelMinSize);
if (patchPosResolution.isValid())
{
const uint directionIdx = PatchUtil::GetDirectionIndex(sourceWorldFlatNormal, PatchUtil::gridCellAngularResolution);
const uint3 positionStorageSpace = PatchUtil::ConvertGridSpaceToStorageSpace(patchPosResolution.positionGridSpace, _GridSize, _CascadeOffsets[patchPosResolution.cascadeIdx]);
const uint cellIdx = PatchUtil::GetCellIndex(patchPosResolution.cascadeIdx, positionStorageSpace, directionIdx, _GridSize, PatchUtil::gridCellAngularResolution);
PatchUtil::PatchIndexResolutionResult resolutionResult = PatchUtil::ResolvePatchIndex(
_RingConfigBuffer,
_RingConfigOffset,
_CellPatchIndices,
_CellAllocationMarks,
cellIdx);
if (resolutionResult.code != PatchUtil::patchIndexResolutionCodeAllocationFailure)
{
PatchUtil::PatchGeometry geo;
geo.position = sourceWorldPosition;
geo.normal = sourceWorldFlatNormal;
_PatchGeometries[resolutionResult.patchIdx] = geo;
}
if (resolutionResult.code == PatchUtil::patchIndexResolutionCodeAllocationSuccess)
{
_PatchCellIndices[resolutionResult.patchIdx] = cellIdx;
PatchUtil::PatchCounterSet counterSet;
PatchUtil::Reset(counterSet);
PatchUtil::SetLastAccessFrame(counterSet, _FrameIdx);
SphericalHarmonics::RGBL1 irradianceSeed = (SphericalHarmonics::RGBL1)0;
if (_FrameIdx != 0)
{
if (_UseMotionVectorSeeding)
{
const float2 threadUvPos = PixelPosToUvPos(fullResPixelPos, rcpFullResScreenSize);
float2 reprojectedThreadUvPos = threadUvPos - _CurrentFullResScreenMotionVectors[fullResPixelPos];
if (all(VECTOR_LOGIC_AND(0.0f < reprojectedThreadUvPos, reprojectedThreadUvPos < 1.0f)))
{
const uint2 reprojectedThreadPixelPos = reprojectedThreadUvPos * fullResScreenSize;
const uint2 seedLowResPixelPos = reprojectedThreadPixelPos / lowResScreenScaling;
const float seedNdcDepth = _PreviousLowResScreenNdcDepths[seedLowResPixelPos];
if (seedNdcDepth != invalidNdcDepth)
{
const float2 seedFullResUvPos = PixelPosToUvPos(seedLowResPixelPos * lowResScreenScaling, rcpFullResScreenSize);
const float3 seedWorldPosition = ComputeWorldSpacePosition(seedFullResUvPos, seedNdcDepth, _PreviousClipToWorldTransform);
const float voxelSize = PatchUtil::GetVoxelSize(_VoxelMinSize, patchPosResolution.cascadeIdx);
const float patchPlaneToSeedPositionDistance = dot(sourceWorldFlatNormal, seedWorldPosition - sourceWorldPosition);
if (patchPlaneToSeedPositionDistance < voxelSize)
{
irradianceSeed = IrradianceCompression::LoadAndDecompress(
_PreviousLowResScreenIrradiancesL0,
_PreviousLowResScreenIrradiancesL10,
_PreviousLowResScreenIrradiancesL11,
_PreviousLowResScreenIrradiancesL12,
seedLowResPixelPos);
if (PatchUtil::IsValid(irradianceSeed))
PatchUtil::SetUpdateCount(counterSet, PatchUtil::updateMax / 2);
#ifdef SEED_DEBUGGING
else
{
irradianceSeed = (SphericalHarmonics::RGBL1)0;
PatchUtil::SetUpdateCount(counterSet, PatchUtil::updateMax);
irradianceSeed.l0 = float3(10, 0, 0);
}
#endif
}
#ifdef SEED_DEBUGGING
else
{
PatchUtil::SetUpdateCount(counterSet, PatchUtil::updateMax);
irradianceSeed.l0 = float3(0, 0, 10);
}
#endif
}
}
}
else
{
irradianceSeed = IrradianceCompression::LoadAndDecompress(
_PreviousLowResScreenIrradiancesL0,
_PreviousLowResScreenIrradiancesL10,
_PreviousLowResScreenIrradiancesL11,
_PreviousLowResScreenIrradiancesL12,
lowResPixelPos);
if (PatchUtil::IsValid(irradianceSeed))
PatchUtil::SetUpdateCount(counterSet, PatchUtil::updateMax / 2);
}
#ifdef SEED_DEBUGGING
// For debugging: Add color to unseeded patches.
if (PatchUtil::GetUpdateCount(counterSet) == 0)
{
PatchUtil::SetUpdateCount(counterSet, PatchUtil::updateMax);
irradianceSeed.l0 = float3(0, 10, 0);
}
#endif
}
_PatchIrradiances0[resolutionResult.patchIdx] = irradianceSeed;
_PatchIrradiances1[resolutionResult.patchIdx] = irradianceSeed;
_PatchCounterSets[resolutionResult.patchIdx] = counterSet;
}
}
}