in unity/Assets/PostProcessingV2/Runtime/Effects/MultiScaleVO.cs [259:346]
void PushRenderCommands(CommandBuffer cmd, int source, int destination, Vector3 sourceSize, float tanHalfFovH)
{
// Here we compute multipliers that convert the center depth value into (the reciprocal
// of) sphere thicknesses at each sample location. This assumes a maximum sample radius
// of 5 units, but since a sphere has no thickness at its extent, we don't need to
// sample that far out. Only samples whole integer offsets with distance less than 25
// are used. This means that there is no sample at (3, 4) because its distance is
// exactly 25 (and has a thickness of 0.)
// The shaders are set up to sample a circular region within a 5-pixel radius.
const float kScreenspaceDiameter = 10f;
// SphereDiameter = CenterDepth * ThicknessMultiplier. This will compute the thickness
// of a sphere centered at a specific depth. The ellipsoid scale can stretch a sphere
// into an ellipsoid, which changes the characteristics of the AO.
// TanHalfFovH: Radius of sphere in depth units if its center lies at Z = 1
// ScreenspaceDiameter: Diameter of sample sphere in pixel units
// ScreenspaceDiameter / BufferWidth: Ratio of the screen width that the sphere actually covers
float thicknessMultiplier = 2f * tanHalfFovH * kScreenspaceDiameter / sourceSize.x;
if (RuntimeUtilities.isSinglePassStereoEnabled)
thicknessMultiplier *= 2f;
// This will transform a depth value from [0, thickness] to [0, 1].
float inverseRangeFactor = 1f / thicknessMultiplier;
// The thicknesses are smaller for all off-center samples of the sphere. Compute
// thicknesses relative to the center sample.
for (int i = 0; i < 12; i++)
m_InvThicknessTable[i] = inverseRangeFactor / m_SampleThickness[i];
// These are the weights that are multiplied against the samples because not all samples
// are equally important. The farther the sample is from the center location, the less
// they matter. We use the thickness of the sphere to determine the weight. The scalars
// in front are the number of samples with this weight because we sum the samples
// together before multiplying by the weight, so as an aggregate all of those samples
// matter more. After generating this table, the weights are normalized.
m_SampleWeightTable[ 0] = 4 * m_SampleThickness[ 0]; // Axial
m_SampleWeightTable[ 1] = 4 * m_SampleThickness[ 1]; // Axial
m_SampleWeightTable[ 2] = 4 * m_SampleThickness[ 2]; // Axial
m_SampleWeightTable[ 3] = 4 * m_SampleThickness[ 3]; // Axial
m_SampleWeightTable[ 4] = 4 * m_SampleThickness[ 4]; // Diagonal
m_SampleWeightTable[ 5] = 8 * m_SampleThickness[ 5]; // L-shaped
m_SampleWeightTable[ 6] = 8 * m_SampleThickness[ 6]; // L-shaped
m_SampleWeightTable[ 7] = 8 * m_SampleThickness[ 7]; // L-shaped
m_SampleWeightTable[ 8] = 4 * m_SampleThickness[ 8]; // Diagonal
m_SampleWeightTable[ 9] = 8 * m_SampleThickness[ 9]; // L-shaped
m_SampleWeightTable[10] = 8 * m_SampleThickness[10]; // L-shaped
m_SampleWeightTable[11] = 4 * m_SampleThickness[11]; // Diagonal
// Zero out the unused samples.
// FIXME: should we support SAMPLE_EXHAUSTIVELY mode?
m_SampleWeightTable[0] = 0;
m_SampleWeightTable[2] = 0;
m_SampleWeightTable[5] = 0;
m_SampleWeightTable[7] = 0;
m_SampleWeightTable[9] = 0;
// Normalize the weights by dividing by the sum of all weights
var totalWeight = 0f;
foreach (float w in m_SampleWeightTable)
totalWeight += w;
for (int i = 0; i < m_SampleWeightTable.Length; i++)
m_SampleWeightTable[i] /= totalWeight;
// Set the arguments for the render kernel.
var cs = m_Resources.computeShaders.multiScaleAORender;
int kernel = cs.FindKernel("main_interleaved");
cmd.SetComputeFloatParams(cs, "gInvThicknessTable", m_InvThicknessTable);
cmd.SetComputeFloatParams(cs, "gSampleWeightTable", m_SampleWeightTable);
cmd.SetComputeVectorParam(cs, "gInvSliceDimension", new Vector2(1f / sourceSize.x, 1f / sourceSize.y));
cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector2(-1f / m_Settings.thicknessModifier.value, m_Settings.intensity.value));
cmd.SetComputeTextureParam(cs, kernel, "DepthTex", source);
cmd.SetComputeTextureParam(cs, kernel, "Occlusion", destination);
// Calculate the thread group count and add a dispatch command with them.
uint xsize, ysize, zsize;
cs.GetKernelThreadGroupSizes(kernel, out xsize, out ysize, out zsize);
cmd.DispatchCompute(
cs, kernel,
((int)sourceSize.x + (int)xsize - 1) / (int)xsize,
((int)sourceSize.y + (int)ysize - 1) / (int)ysize,
((int)sourceSize.z + (int)zsize - 1) / (int)zsize
);
}