Rasagar/Library/PackageCache/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurMotionVecPrep.compute
2024-08-26 23:07:20 +03:00

182 lines
6.2 KiB
Plaintext

#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/MotionBlurCommon.hlsl"
#pragma kernel MotionVecPreppingCS MOTION_VEC_PREPPING
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#define SKIP_PREPPING_IF_NOT_NEEDED defined(PLATFORM_SUPPORTS_WAVE_INTRINSICS)
// Special clamps for camera component.
#pragma multi_compile NO_SPECIAL_CLAMP CAMERA_ROT_CLAMP CAMERA_TRANS_CLAMP CAMERA_FULL_CLAMP CAMERA_SEPARATE_CLAMP CAMERA_DISABLE_CAMERA
// We use polar coordinates. This has the advantage of storing the length separately and we'll need the length several times.
float2 EncodeMotionVector(float2 motionVec)
{
float motionVecLen = length(motionVec);
if (motionVecLen < 0.0001)
{
return 0.0;
}
else
{
float theta = atan2(motionVec.y, motionVec.x) * (0.5 / PI) + 0.5;
return float2(motionVecLen, theta);
}
}
float2 ClampMotionVec(float2 motionVec, float maxMotionVec)
{
float len = length(motionVec);
float newLen = min(len, maxMotionVec);
return (len > 1e-4f && newLen > 1e-4f) ? newLen * (motionVec * rcp(len)) : 0.0;
}
float2 GetDeltaNDCVec(float4 positionWS, float4 prevPosWS, float4x4 currM, float4x4 prevM)
{
float4 clipWP = mul(currM, positionWS);
float4 clipPrevWP = mul(prevM, prevPosWS);
clipWP.xy /= clipWP.w;
clipPrevWP.xy /= clipPrevWP.w;
float2 outDeltaVec = (clipWP.xy - clipPrevWP.xy);
outDeltaVec *= 0.5f;
#if UNITY_UV_STARTS_AT_TOP
outDeltaVec.y = -outDeltaVec.y;
#endif
return outDeltaVec;
}
// Prep motion vectors so that the velocity due to rotation is clamped more lightly
// A bit of code duplication but keeping separate make it clearer.
#ifdef NO_SPECIAL_CLAMP
float2 ComputeMotionVec(PositionInputs posInput, float2 sampledMotionVec)
{
return ClampMotionVec(sampledMotionVec * _MotionBlurIntensity, _MotionBlurMaxMotionVec);
}
#elif defined(CAMERA_DISABLE_CAMERA)
float2 ComputeMotionVec(PositionInputs posInput, float2 sampledMotionVec)
{
float4 worldPos = float4(posInput.positionWS, 1.0);
float4 prevPos = worldPos;
float2 cameraMv = GetDeltaNDCVec(worldPos, prevPos, UNITY_MATRIX_UNJITTERED_VP, UNITY_MATRIX_PREV_VP);
return ClampMotionVec((sampledMotionVec - cameraMv) * _MotionBlurIntensity, _MotionBlurMaxMotionVec);
}
#elif defined(CAMERA_TRANS_CLAMP) || defined(CAMERA_SEPARATE_CLAMP)
float2 ComputeMotionVec(PositionInputs posInput, float2 sampledMotionVec)
{
float4 worldPos = float4(posInput.positionWS, 1.0);
float4 prevPos = worldPos;
// Calculate translation part
float2 clampedCameraTranslationMV = 0;
float2 cameraTranslationMv = 0;
{
// Note: potentially wrong if projection matrix changes, but should be rare enough and will last only one frame.
cameraTranslationMv = GetDeltaNDCVec(worldPos, worldPos - float4(_PrevCamPosRWS.xyz, 0.0), UNITY_MATRIX_UNJITTERED_VP, UNITY_MATRIX_UNJITTERED_VP);
clampedCameraTranslationMV = ClampMotionVec(cameraTranslationMv * _MotionBlurIntensity, _CameraTranslationClampNDC);
}
float2 clampedCameraRotationMV = 0;
float2 cameraRotationMv = 0;
#if defined(CAMERA_SEPARATE_CLAMP)
{
cameraRotationMv = GetDeltaNDCVec(worldPos, worldPos, _CurrVPMatrixNoTranslation, _PrevVPMatrixNoTranslation);
clampedCameraRotationMV = ClampMotionVec(cameraRotationMv * _MotionBlurIntensity, _CameraRotationClampNDC);
}
#endif
float2 mvWithoutCameraComponents = sampledMotionVec - cameraRotationMv - cameraTranslationMv;
mvWithoutCameraComponents = ClampMotionVec(mvWithoutCameraComponents * _MotionBlurIntensity, _MotionBlurMaxMotionVec);
return mvWithoutCameraComponents + clampedCameraTranslationMV + clampedCameraRotationMV;
}
#elif defined(CAMERA_ROT_CLAMP) || defined(CAMERA_FULL_CLAMP)
#if defined(CAMERA_ROT_CLAMP)
#define _CameraClampThreshold _CameraRotationClampNDC
#else
#define _CameraClampThreshold _CameraFullClampNDC
#endif
float2 ComputeMotionVec(PositionInputs posInput, float2 sampledMotionVec)
{
float4 worldPos = float4(posInput.positionWS, 1.0);
float4 prevPos = worldPos;
float4x4 prevVP = UNITY_MATRIX_PREV_VP;
float4x4 currVP = UNITY_MATRIX_UNJITTERED_VP;
#if defined(CAMERA_ROT_CLAMP)
prevVP = _PrevVPMatrixNoTranslation;
currVP = _CurrVPMatrixNoTranslation;
#endif
float2 cameraMv = GetDeltaNDCVec(worldPos, prevPos, currVP, prevVP);
float2 velocityWithoutCameraComponent = sampledMotionVec - cameraMv;
cameraMv *= _MotionBlurIntensity;
float2 clampedCameraMotionVec = ClampMotionVec(cameraMv, _CameraClampThreshold);
return ClampMotionVec(velocityWithoutCameraComponent * _MotionBlurIntensity, _MotionBlurMaxMotionVec) + clampedCameraMotionVec;
}
#else
#error
#endif
[numthreads(8, 8,1)]
void MotionVecPreppingCS(uint3 dispatchThreadId : SV_DispatchThreadID)
{
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
float3 motionVecAndDepth = 0.0f;
float2 motionVecUV = FromOutputPosSSToPreupsampleUV(dispatchThreadId.xy);
motionVecUV = ClampAndScaleUVForPoint(motionVecUV);
float4 motionVecBufferSample = SAMPLE_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, s_point_clamp_sampler, motionVecUV, 0);
// if we have a value > 1.0f, it means we have selected the "no motion option", hence we force motionVec 0.
bool forceNoMotion = PixelSetAsNoMotionVectors(motionVecBufferSample);
float2 motionVec;
DecodeMotionVector(motionVecBufferSample, motionVec);
float depth = LoadCameraDepth(FromOutputPosSSToPreupsamplePosSS(dispatchThreadId.xy));
if ( !forceNoMotion
#if SKIP_PREPPING_IF_NOT_NEEDED
&& WaveActiveAnyTrue(dot(motionVec, motionVec) * _ScreenMagnitudeSq > _MinMotionVecThresholdSq)
#endif
)
{
PositionInputs posInput = GetPositionInput(dispatchThreadId.xy, _PostProcessScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
float2 finalMotionVec = ComputeMotionVec(posInput, motionVec);
motionVecAndDepth.xy = EncodeMotionVector(finalMotionVec);
motionVecAndDepth.z = posInput.linearDepth;
}
else
{
motionVecAndDepth.z = LinearEyeDepth(depth, _ZBufferParams);
}
_MotionVecAndDepth[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = motionVecAndDepth;
}