Unity中无需后处理实现运动模糊及着色器获取前一位置问询
在Unity着色器中获取顶点上一帧位置(Previous Position)的实现方法
要获取顶点的上一帧位置,核心逻辑是手动缓存当前帧的顶点位置到纹理中,下一帧读取该纹理得到上一帧数据——Unity不会自动保留上一帧的顶点状态,必须通过离线存储实现。
具体实现步骤
1. 初始化位置缓存纹理
在C#脚本中创建一个浮点格式的RenderTexture,用于存储每一帧的顶点位置(浮点格式能避免精度丢失):
public RenderTexture prevPositionRT; void Start() { prevPositionRT = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGBFloat); prevPositionRT.Create(); }
2. 渲染当前帧位置到缓存纹理
写一个专用着色器,将当前帧顶点的裁剪空间位置(已包含相机视图投影变换,无需额外处理相机运动)归一化后输出到缓存纹理:
Shader "Custom/StorePosition" { SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; float4 clipPos : TEXCOORD0; }; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); // 把裁剪空间位置归一化到[0,1]范围,适配纹理存储 o.clipPos = o.pos * 0.5 + 0.5; return o; } fixed4 frag (v2f i) : SV_Target { return fixed4(i.clipPos.xyz, 1); } ENDCG } } }
在C#脚本的每一帧,先使用这个着色器渲染场景,将结果写入prevPositionRT。
3. 在目标着色器中读取上一帧位置
在需要计算运动模糊的着色器中,采样缓存纹理获取上一帧位置,再转换回原始空间:
Shader "Custom/MotionBlur" { Properties { _MainTex ("Texture", 2D) = "white" {} _PrevPositionTex ("Previous Position Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } 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 clipPos : TEXCOORD1; float4 pos : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _PrevPositionTex; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 当前帧裁剪位置归一化,用于采样上一帧纹理 o.clipPos = o.pos * 0.5 + 0.5; return o; } fixed4 frag (v2f i) : SV_Target { // 采样上一帧的归一化裁剪位置 float4 prevClipPos = tex2D(_PrevPositionTex, i.clipPos.xy); // 转换回原始裁剪空间 prevClipPos = prevClipPos * 2 - 1; // 计算运动向量(当前帧与上一帧的位置差) float2 motionVec = i.clipPos.xy - prevClipPos.xy; // 后续运动模糊逻辑(基于运动向量采样多帧颜色等) fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
关键注意事项
- 空间一致性:存储和读取的位置必须使用同一空间(比如都用裁剪空间),否则运动向量计算会出错。
- 纹理精度:必须使用浮点格式RenderTexture,避免位置数据被压缩导致精度丢失。
- 相机同步:裁剪空间位置已包含相机的视图投影变换,无需额外处理相机的移动、旋转,能直接得到正确的运动向量。
内容的提问来源于stack exchange,提问作者Strawberry
相关产品推荐
相关产品推荐

