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

68 lines
2.8 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
///////
// Typical usage of the Sobol functions for one or more points per pixel
// uint2 SobolBase = SobolPixel(uint2(SvPosition.xy)); // First sample for this pixel
// for(int i = 0; i < N; ++i)
// float2 Point = float2(SobolIndex(SobolBase, i)) / 0x10000; // Points as [0,1) x [0,1)
//
// Typical usage for one or more points per frame
// uint2 SobolBase = SobolPixel(uint2(SvPosition.xy)); // Frame 0, point 0 for this pixel
// uint2 SobolFrame = SobolIndex(SobolBase, View.StateFrameIndexMod8, 3); // Least significant bits for frame
// for(int i = 0; i < N; ++i)
// float2 Point = float2(SobolIndex(SobolFrame, i << 3)) / 0x10000; // Higher-order bits for point within frame
//
// For additional independent point sets
// uint2 SobolBase2 = SobolBase ^ RandSeed; // where RandSeed is a uint2 with values in 0 to 0xffff
// Compute a Sobol-distributed point from a 256x256 pixel grid one pixel in that grid
// @param Pixel Pixel/cell position in the 256x256 grid
// @return Sobol position relative to the pixel corner, with components in the range 0 to 0xffff
uint2 SobolPixel(uint2 Pixel)
{
// look up for pixel
int3 SobolLo = int3(Pixel & 0xfu, 0);
int3 SobolHi = int3((Pixel >> 4u) & 0xfu, 0) + int3(16, 0, 0);
uint Packed = View.SobolSamplingTexture.Load(SobolLo) ^ View.SobolSamplingTexture.Load(SobolHi);
return uint2(Packed, Packed << 8u) & 0xff00u;
}
// Evaluate additional Sobol points within a pixel
// @param Base Base Sobol point for this pixel
// @param Index Which 2D Sobol point to return
// @param Bits Optional max bits in index (to avoid extra calculation)
// @return Sobol position in the range 0 to 0xffff
uint2 SobolIndex(uint2 Base, int Index, int Bits = 10)
{
uint2 SobolNumbers[10] = {
uint2(0x8680u, 0x4c80u), uint2(0xf240u, 0x9240u), uint2(0x8220u, 0x0e20u), uint2(0x4110u, 0x1610u), uint2(0xa608u, 0x7608u),
uint2(0x8a02u, 0x280au), uint2(0xe204u, 0x9e04u), uint2(0xa400u, 0x4682u), uint2(0xe300u, 0xa74du), uint2(0xb700u, 0x9817u),
};
uint2 Result = Base;
UNROLL for (int b = 0; b < 10 && b < Bits; ++b)
{
Result ^= (Index & (1u << b)) ? SobolNumbers[b] : 0;
}
return Result;
}
/** Returns an unique sobol sample for the frame. */
uint2 ComputePixelUniqueSobolRandSample(uint2 PixelCoord)
{
const uint TemporalBits = 10;
uint FrameIndexMod1024 = ReverseBitsN(GetPowerOfTwoModulatedFrameIndex(1u << TemporalBits), TemporalBits);
uint2 SobolBase = SobolPixel(PixelCoord);
return SobolIndex(SobolBase, FrameIndexMod1024, TemporalBits);
}
/** Maps a sobol random generated sample to 2D unit square. */
float2 SobolIndexToUniformUnitSquare(uint2 SobolRand)
{
return float2(SobolRand) * rcp(65536.0) + rcp(65536.0 * 2.0);
}