Skip to content

Instantly share code, notes, and snippets.

@michael-sacco
Last active June 17, 2025 21:57
Show Gist options
  • Select an option

  • Save michael-sacco/4d13381cb3322a457a7993012147273a to your computer and use it in GitHub Desktop.

Select an option

Save michael-sacco/4d13381cb3322a457a7993012147273a to your computer and use it in GitHub Desktop.
Unity Get Camera Motion Vectors in Custom Pass for Universal Render Pipeline (URP)
#ifndef GETCAMERAMOTIONVECTORS_INCLUDE
#define GETCAMERAMOTIONVECTORS_INCLUDE
#if defined(USING_STEREO_MATRICES)
float4x4 _PrevViewProjMStereo[2];
#define _PrevViewProjM _PrevViewProjMStereo[unity_StereoEyeIndex]
#define _ViewProjM unity_MatrixVP
#else
float4x4 _ViewProjM;
float4x4 _PrevViewProjM;
#endif
void GetCameraMotionVectors_float(float4 UV, float3 positionOS, out float2 velocity)
{
velocity = 0;
#ifndef SHADERGRAPH_PREVIEW
float4 positionCS = TransformObjectToHClip(positionOS);
float4 projPos = positionCS * 0.5;
projPos.xy = projPos.xy + projPos.w;
half depth = 0.0;
#if UNITY_REVERSED_Z
depth = 1.0;
#endif
float3 viewPos = ComputeViewSpacePosition(projPos.xy, depth, unity_CameraInvProjection);
float3 viewDirectionTemp = mul(unity_CameraInvProjection, float4(UV.xy * 2 - 1, 0.0, -1));
float3 viewVector = mul(unity_CameraToWorld, float4(viewDirectionTemp, 0.0));
float3 rayDirection = viewVector / length(viewVector);
float4 worldPos = float4(mul(unity_CameraToWorld, float4(viewPos, 1.0)).xyz, 1.0);
float4 prevPos = worldPos;
float4 prevClipPos = mul(_PrevViewProjM, prevPos);
float4 curClipPos = mul(_ViewProjM, worldPos);
float2 prevPosCS = prevClipPos.xy / prevClipPos.w;
float2 curPosCS = curClipPos.xy / curClipPos.w;
velocity = prevPosCS - curPosCS;
#if UNITY_UV_STARTS_AT_TOP == 0
velocity.y = -velocity.y;
#endif
velocity.xy *= 0.5;
#endif
}
#endif
using UnityEngine;
using UnityEngine.Rendering;
// Note: This form of assigning view projection matrices to shader has been removed from Altos.
// Now we assign the view projection matrices directly to specific material in the Render Pass.
public class WriteGpuVpToShader : MonoBehaviour
{
private Matrix4x4 gpuVPLast;
private Camera cam;
private void Start()
{
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
cam = Camera.main;
cam.depthTextureMode |= DepthTextureMode.MotionVectors;
}
void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
{
var gpuProj = GL.GetGPUProjectionMatrix(cam.projectionMatrix, true);
var gpuView = cam.worldToCameraMatrix;
var gpuVP = gpuProj * gpuView;
Shader.SetGlobalMatrix("_ViewProjM", gpuVP);
if (gpuVPLast != null)
Shader.SetGlobalMatrix("_PrevViewProjM", gpuVPLast);
gpuVPLast = gpuVP;
}
void OnDestroy()
{
RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment