I noticed that Unity does not provide motion vectors for objects with materials that contain a custom shader (HLSL) in HDRP if this shader do not provide a MotionVector pass. The built-in renderpipeline provided motion vectors for all objects with custom shaders without providing a MotionVector pass. Is this intended behavior for shaders in HDRP or did I miss something?
The built in pipeline used RenderWithShader to render many of the things that now require extra passes in every shader.
I just used the following bit of code as my vertex shader inside of a full screen shader (for Custom Passes).
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl"
float4 FullScreenMotionVectorsPass(Varyings varyings)
: SV_TARGET
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(varyings);
float2 motion = LOAD_TEXTURE2D_X_LOD(_CameraMotionVectorsTexture, varyings.positionCS.xy, 0).rg;
return float4(motion, 0.0, 1.0);
}
I didn’t have to define _CameraMotionVectorsTexture at any point inside of my shader. In fact, the only spot in my code that that even mentions it was the call to LOAD_TEXTURE2D_X_LOB(…). All I did inside my CustomPass was make a call to CoreUtils.DrawFullScreen(…), where I passed in a material that was created from my full screen shader. _CameraMotionVectorsTexture
is the buffer that the post processing blur effect reads from; I found it by digging through the source code of Unity’s Graphics repo on GitHub.
I have used quite a few materials that were created from Shader Graphs in my projects, and I’ve never had an issue with pulling the motion vectors due to using a custom material. There are a few things to keep in mind, like motion vectors are 16 bit floats, so you should probably switch your buffer to use 16 bits per channel. Also, the motion vectors are normalized to screen space, so they’ll have a range between -1.0 and +1.0.
I have also learned from first hand experience that if you try to normalize your motion vectors to 01-Space by doing a ((value / 2.0) + 0.5) conversion, then that +0.5 will cause the loss of quite a few of your motion vector values. 16-bit floating point values don’t have much when it comes to significant digits. And, significant digits matter because floating point values are stored using scientific notion. When doing addition and subtraction operations, you need to match the exponents. So something like 0.5 + 0.000000032
will be turned into 5.0 * 10^-1 + 0.00000032 * 10^-1
. Normally, a value like 0.000000032
will be stored as 3.2 * 10^-8
, but when you turn it into 0.00000032 * 10^-1
, that 32 at the end gets dropped because a 16 bit float doesn’t contain enough significant digits. And we end up with a result of 0.5, which is a motion vector of 0.