216 lines
7.7 KiB
Plaintext
216 lines
7.7 KiB
Plaintext
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
|
|
#pragma kernel TileNeighbourhood NEIGHBOURHOOD_PASS
|
|
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurTileCommon.hlsl"
|
|
|
|
#pragma multi_compile _ SCATTERING
|
|
|
|
#ifdef SCATTERING
|
|
|
|
// TODO: Consider a conservative line rasterization.
|
|
// Line drawing algorithms.
|
|
#if 0
|
|
void Bresenham(int2 center, float2 lineToDraw, uint centerInfo)
|
|
{
|
|
int2 maxCoords = int2(_TileTargetSize.xy - 1);
|
|
|
|
// Determine start and end point of the line. Forward
|
|
int2 startPoint = center;
|
|
int2 endPoint = int2(ceil(startPoint.x + lineToDraw.x), ceil(startPoint.y + lineToDraw.y));
|
|
endPoint = clamp(endPoint, int2(0, 0), maxCoords);
|
|
|
|
int2 delta = int2(abs(startPoint - endPoint));
|
|
int2 steps = int2(startPoint.x < endPoint.x ? 1 : -1, startPoint.y < endPoint.y ? 1 : -1);
|
|
int tMax = (delta.x > delta.y ? delta.x : -delta.y) / 2;
|
|
|
|
int x = startPoint.x;
|
|
int y = startPoint.y;
|
|
|
|
for (int i = 0; i < 32; ++i)
|
|
{
|
|
if (x >= endPoint.x && y >= endPoint.y)
|
|
{
|
|
break;
|
|
}
|
|
if (tMax > -delta.x)
|
|
{
|
|
tMax -= delta.y;
|
|
x += steps.x;
|
|
}
|
|
if (tMax < delta.y)
|
|
{
|
|
tMax += delta.x;
|
|
y += steps.y;
|
|
}
|
|
|
|
|
|
InterlockedMax(_TileToScatterMax[COORD_TEXTURE2D_X(int2(x, y))], uint(centerInfo));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Derived from Voxel traversal along a 3D line (https://dl.acm.org/doi/10.5555/180895.180926)
|
|
void Cohen(int2 center, float2 lineToDraw, uint centerInfo)
|
|
{
|
|
// We push the extremes by one to be safer. Not great, but works better than not doing it.
|
|
int2 startPoint = center - 1;
|
|
int2 dir = ceil(lineToDraw + 1);
|
|
int2 signs = int2(sign(dir.x), sign(dir.y));
|
|
|
|
int2 a = dir * signs;
|
|
int2 b = 2 * a;
|
|
|
|
int2 pos = startPoint;
|
|
|
|
int e = a.y - a.x;
|
|
int l = (a.x + a.y);
|
|
|
|
for (int i = 0; i < l; i++)
|
|
{
|
|
if (e < 0)
|
|
{
|
|
pos.x += signs.x;
|
|
e += b.y;
|
|
}
|
|
else
|
|
{
|
|
pos.y += signs.y;
|
|
e -= b.x;
|
|
}
|
|
|
|
InterlockedMax(_TileToScatterMax[COORD_TEXTURE2D_X(pos)], uint(centerInfo));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void DDA(int2 center, float2 lineToDraw, uint centerInfo)
|
|
{
|
|
int2 maxCoords = int2(_TileTargetSize.xy);
|
|
|
|
int2 startPoint = center;
|
|
int2 endPoint = int2(ceil(startPoint.x + lineToDraw.x), ceil(startPoint.y + lineToDraw.y));
|
|
endPoint = clamp(endPoint, int2(0, 0), maxCoords);
|
|
|
|
bool permute = false;
|
|
if (abs(lineToDraw.x) < abs(lineToDraw.y))
|
|
{
|
|
permute = true;
|
|
lineToDraw = lineToDraw.yx;
|
|
startPoint = startPoint.yx;
|
|
endPoint = endPoint.yx;
|
|
}
|
|
float dirSign = sign(lineToDraw.x);
|
|
|
|
float invDeltaX = dirSign / lineToDraw.x;
|
|
float2 step = float2(dirSign, lineToDraw.y * invDeltaX);
|
|
|
|
float end = endPoint.x * dirSign;
|
|
float2 currPoint = startPoint;
|
|
|
|
const int maxIter = 64;
|
|
for (int i = 0; ((currPoint.x * dirSign) <= end) && (i < maxIter); ++i)
|
|
{
|
|
currPoint += step;
|
|
float2 hitPixel = permute ? currPoint.yx : currPoint;
|
|
hitPixel = clamp(hitPixel, 0, _TileTargetSize.xy);
|
|
InterlockedMax(_TileToScatterMax[COORD_TEXTURE2D_X(ceil(hitPixel))], uint(centerInfo));
|
|
}
|
|
}
|
|
|
|
#define USE_NEIGHBOURHOOD_MIN 0 // Note: the neighbourhood building for min is done during merge pass as we need to have easy access to maxVal
|
|
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void TileNeighbourhood(uint3 dispatchID : SV_DispatchThreadID, uint gid : SV_GroupIndex, uint2 groupThreadId : SV_GroupThreadID, uint3 groupID : SV_GroupID)
|
|
{
|
|
#ifndef SHADER_API_METAL
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchID.z);
|
|
int2 id = dispatchID.xy;
|
|
int2 maxCoords = int2(_TileTargetSize.xy - 1);
|
|
|
|
if (any(id > maxCoords)) return;
|
|
|
|
// Sample the motionVec at this tile.
|
|
uint packedTileInfo = _TileToScatterMax[COORD_TEXTURE2D_X(id)];
|
|
float minMotionVec = _TileToScatterMin[COORD_TEXTURE2D_X(id)];
|
|
|
|
float2 MotionVecData = UnpackMotionVec(packedTileInfo);
|
|
|
|
// Covert to a per pixel motionVec.
|
|
float2 maxMotionVectorInTiles = DecodeMotionVectorFromPacked(MotionVecData.xy) * _TileTargetSize.xy * 0.5f;
|
|
|
|
// If the central motionVec is small, no need to spread it.
|
|
if (MotionVecLengthInPixelsFromEncoded(MotionVecData) > 0.5f)
|
|
{
|
|
// Spread Forward
|
|
Cohen(id, maxMotionVectorInTiles, packedTileInfo);
|
|
// Spread Backward
|
|
Cohen(id, -maxMotionVectorInTiles, packedTileInfo);
|
|
}
|
|
|
|
// TODO: We need to find a better min motionVec determination.
|
|
#if USE_NEIGHBOURHOOD_MIN
|
|
// Find min of the tile in the 1-ring neighbourhood? This is incorrect, but might be worth perf wise.
|
|
float v0 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, 1), int2(0, 0), maxCoords))];
|
|
float v1 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(0, 1), int2(0, 0), maxCoords))];
|
|
float v2 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, 1), int2(0, 0), maxCoords))];
|
|
|
|
float v3 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, 0), int2(0, 0), maxCoords))];
|
|
float v4 = minMotionVec;
|
|
float v5 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, 0), int2(0, 0), maxCoords))];
|
|
|
|
float v6 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, -1), int2(0, 0), maxCoords))];
|
|
float v7 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(0, -1), int2(0, 0), maxCoords))];
|
|
float v8 = _TileToScatterMin[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, -1), int2(0, 0), maxCoords))];
|
|
|
|
float minMotionVec0 = Min3(v0, v1, v2);
|
|
float minMotionVec1 = Min3(v3, v4, v5);
|
|
float minMotionVec2 = Min3(v6, v7, v8);
|
|
minMotionVec = Min3(minMotionVec0, minMotionVec1, minMotionVec2);
|
|
#endif
|
|
_TileToScatterMin[COORD_TEXTURE2D_X(id)] = minMotionVec;
|
|
#endif
|
|
}
|
|
|
|
|
|
#else // SCATTERING
|
|
|
|
RW_TEXTURE2D_X(float3, _TileMaxNeighbourhood);
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void TileNeighbourhood(uint3 dispatchID : SV_DispatchThreadID, uint gid : SV_GroupIndex, uint2 groupThreadId : SV_GroupThreadID, uint3 groupID : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchID.z);
|
|
int2 id = dispatchID.xy;
|
|
int2 maxCoords = int2(_TileTargetSize.xy - 1);
|
|
|
|
float3 centralSample = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(id.xy + uint2(0, 0))].xyz;
|
|
|
|
float3 v0 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, 1), int2(0, 0), maxCoords))].xyz;
|
|
float3 v1 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(0, 1), int2(0, 0), maxCoords))].xyz;
|
|
float3 v2 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, 1), int2(0, 0), maxCoords))].xyz;
|
|
|
|
float3 v3 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, 0), int2(0, 0), maxCoords))].xyz;
|
|
float3 v4 = centralSample.xyz;
|
|
float3 v5 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, 0), int2(0, 0), maxCoords))].xyz;
|
|
|
|
float3 v6 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(-1, -1), int2(0, 0), maxCoords))].xyz;
|
|
float3 v7 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(0, -1), int2(0, 0), maxCoords))].xyz;
|
|
float3 v8 = _TileMinMaxMotionVec[COORD_TEXTURE2D_X(clamp(id.xy + int2(1, -1), int2(0, 0), maxCoords))].xyz;
|
|
|
|
|
|
float2 maxMotionVec0 = MaxMotionVec(v0.xy, MaxMotionVec(v1.xy, v2.xy));
|
|
float2 maxMotionVec1 = MaxMotionVec(v3.xy, MaxMotionVec(v4.xy, v5.xy));
|
|
float2 maxMotionVec2 = MaxMotionVec(v6.xy, MaxMotionVec(v7.xy, v8.xy));
|
|
|
|
float minMotionVec0 = Min3(v0.z, v1.z, v2.z);
|
|
float minMotionVec1 = Min3(v3.z, v4.z, v5.z);
|
|
float minMotionVec2 = Min3(v6.z, v7.z, v8.z);
|
|
|
|
|
|
_TileMaxNeighbourhood[COORD_TEXTURE2D_X(id.xy)] = float3(MaxMotionVec(maxMotionVec0, MaxMotionVec(maxMotionVec1, maxMotionVec2)), Min3(minMotionVec0, minMotionVec1, minMotionVec2));
|
|
}
|
|
|
|
#endif
|