## 在Unity built-in RP中擷取motion vector > 記錄一些我自己查不太到資料、曾經被困擾很久的小問題們 這篇文章主要會說明如何從unity取得motion vector並匯出成圖片。 網路上大部分查到的資料會是使用URP或HDRP,但是unity其實有內建的`_CameraMotionVectorsTexture`可以在built-in RP中得到motion vector的資料。 首先需要enable motion vectors和depth才能使用`_CameraMotionVectorsTexture`。 ```csharp motionVectorCamera = GetComponent<Camera>(); motionVectorCamera.depthTextureMode = DepthTextureMode.Depth | DepthTextureMode.MotionVectors; ``` 創建一個RenderTexture來保存。 ```csharp currentFrameTexture = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGBFloat); currentFrameTexture.enableRandomWrite = true; currentFrameTexture.Create(); ``` 然後在onRenderImage() ```csharp private void OnRenderImage(RenderTexture src, RenderTexture dest){ CaptureFrame(src, dest, motionVectorMaterial, PATH); } ``` ```csharp private void CaptureFrame(RenderTexture src, RenderTexture dest, Material shaderProgram, string filepath){ // render the current frame's render to the new RenderTexture Graphics.Blit(src, currentFrameTexture, shaderProgram); // save the frame's render to a Texture2D Texture2D tex = new Texture2D(currentFrameTexture.width, currentFrameTexture.height, TextureFormat.RGBAFloat, false); tex.ReadPixels(new Rect(0, 0, currentFrameTexture.width, currentFrameTexture.height), 0, 0); tex.Apply(); // save those data to exr file byte[] exrBytes = tex.EncodeToEXR(); System.IO.File.WriteAllBytes(filepath + ".exr", exrBytes); Destroy(tex); Graphics.Blit(src, dest); } ``` 這邊是匯出成EXR檔,也可以改成PNG或TXT之類的。 這邊用到了一個shaderProgram的Material,接下來就來看shader的部分: ```shader= Shader "Custom/MotionVectorShader" { Properties { _MainTex("Current Frame", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; sampler2D _CameraMotionVectorsTexture; float4 _CameraMotionVectorsTexture_TexelSize; float4 _CameraMotionVectorsTexture_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _CameraMotionVectorsTexture); return o; } half4 frag(v2f i) : SV_Target { // Fetch motion vectors from Unity's built-in motion vector buffer float2 motionVector = tex2D(_CameraMotionVectorsTexture, i.uv).rg; float2 color = tex2D(_MainTex, i.uv).rg; // for visualizing motionVector = motionVector * 10 + 0.5; return half4(motionVector.x, motionVector.y, 0, 1); } ENDCG } } } ``` 這樣就成功地從`_CameraMotionVectorsTexture`拿到motion vector的資料了。