Unity Shader 学习笔记(23) 运动模糊
来源:互联网 发布:php彩票开奖源码 编辑:程序博客网 时间:2024/05/22 14:52
Unity Shader 学习笔记(23) 运动模糊
参考书籍:《Unity Shader 入门精要》
运动模糊
两种常见方法:
- 积累缓存(accumulation buffer),混合连续多张图像。即需要同一帧里渲染多次场景,性能消耗较大。
- 速度缓存(velocity buffer),存储各个像素当前移动速度,利用该值判断模糊方向和大小,但曲线运动较大时会出现错误。
积累缓存
保持之前渲染结果不断叠加混合,模拟出运动轨迹(幻影)的视觉效果。即不用一帧里多次渲染。
MotionBlur类:
using UnityEngine;public class MotionBlur : PostEffectsBase{ [Range(0.0f, 0.9f)] // 为1的时候完全代替当前帧的渲染结果 public float blurAmount = 0.5f; // 模糊参数 private RenderTexture accumulationTexture; // 保存之前图像的叠加效果 void OnDisable() { DestroyImmediate(accumulationTexture); // 用完就销毁,下一次开始应用这个重新叠加 } void OnRenderImage(RenderTexture src, RenderTexture dest) { if (TargetMaterial != null) { // 创建积累图像 if (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height) { DestroyImmediate(accumulationTexture); accumulationTexture = new RenderTexture(src.width, src.height, 0); accumulationTexture.hideFlags = HideFlags.HideAndDontSave; // 变量不显示在Hierarchy中,也不会保存到场景 Graphics.Blit(src, accumulationTexture); // 原始图像存入积累纹理 } // 表明需要进行一个恢复操作。渲染恢复操作:发生在渲染到纹理,而该纹理有没有被提前情况或销毁情况下。 accumulationTexture.MarkRestoreExpected(); // accumulationTexture就不需要提前清空了 TargetMaterial.SetFloat("_BlurAmount", 1.0f - blurAmount); // 混合当前屏幕和之前存的混合图像 Graphics.Blit(src, accumulationTexture, TargetMaterial); // 最后输出混合图像 Graphics.Blit(accumulationTexture, dest); } else Graphics.Blit(src, dest); }}
Shader:
Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _BlurAmount ("Blur Amount", Float) = 1.0}
SubShader { CGINCLUDE ... // 更新RGB,当前图像。A通道设为模糊值,方便后面混合 fixed4 fragRGB (v2f i) : SV_Target { return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount); } // 更新A,直接返回(保护纹理的A通道,不受混合时透明度影响) half4 fragA (v2f i) : SV_Target { return tex2D(_MainTex, i.uv); } ENDCG ZTest Always Cull Off ZWrite Off Pass { Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB CGPROGRAM #pragma vertex vert #pragma fragment fragRGB ENDCG } Pass { Blend One Zero ColorMask A CGPROGRAM #pragma vertex vert #pragma fragment fragA ENDCG }}
速度缓存
两种方法:
- 把场景所有物体的速度渲染到一张纹理中。缺点是需要修改所有物体的Shader,计算速度并输出到一张纹理。
- 利用深度纹理计算每个像素世界空间下的位置。使用前一帧的变换矩阵计算,就可以得到前一帧该点的位置。通过这两个点就可以计算得到速度值。缺点是要在片元着色器中进行两次矩阵乘法。
使用深度纹理实现
MotionBlurWithDepthTexture类:
using UnityEngine;// 使用深度纹理计算运动模糊public class MotionBlurWithDepthTexture : PostEffectsBase{ [Range(0.0f, 1.0f)] public float blurSize = 0.5f; private Camera targetCamera; public Camera TargetCamera { get { return targetCamera = targetCamera == null ? GetComponent<Camera>() : targetCamera; } } private Matrix4x4 previousViewProjectionMatrix; // 上一帧摄像机的 视角x投影 矩阵 void OnEnable() { TargetCamera.depthTextureMode |= DepthTextureMode.Depth; // 设置状态以获取摄像机的深度纹理 previousViewProjectionMatrix = TargetCamera.projectionMatrix * TargetCamera.worldToCameraMatrix; } void OnRenderImage(RenderTexture src, RenderTexture dest) { if (TargetMaterial != null) { TargetMaterial.SetFloat("_BlurSize", blurSize); // 上一帧的矩阵 TargetMaterial.SetMatrix("_PreviousViewProjectionMatrix", previousViewProjectionMatrix); // 投影矩阵 * 视角矩阵 ,用于给下一帧计算该帧时的位置 Matrix4x4 currentViewProjectionMatrix = TargetCamera.projectionMatrix * TargetCamera.worldToCameraMatrix; // 矩阵取逆,用于计算该帧的位置 Matrix4x4 currentViewProjectionInverseMatrix = currentViewProjectionMatrix.inverse; TargetMaterial.SetMatrix("_CurrentViewProjectionInverseMatrix", currentViewProjectionInverseMatrix); previousViewProjectionMatrix = currentViewProjectionMatrix; } Graphics.Blit(src, dest, TargetMaterial); }}
Shader:
Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _BlurSize ("Blur Size", Float) = 1.0}SubShader { CGINCLUDE ... struct v2f { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; half2 uv_depth : TEXCOORD1; }; v2f vert(appdata_img v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; o.uv_depth = v.texcoord; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv_depth.y = 1 - o.uv_depth.y; #endif return o; } fixed4 frag(v2f i) : SV_Target { // 深度值。通过摄像机的深度纹理和纹理坐标计算(映射)出来 float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth); // 构建像素的NDC坐标,xy像素的纹理坐标映射, float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d * 2 - 1, 1); // 当前帧的 视角x投影 矩阵的逆矩阵变换 float4 D = mul(_CurrentViewProjectionInverseMatrix, H); // 并除w得到世界空间坐标 float4 worldPos = D / D.w; // 当前视角位置 float4 currentPos = H; // 上一帧位置 float4 previousPos = mul(_PreviousViewProjectionMatrix, worldPos); previousPos /= previousPos.w; // 前一帧和当前帧位置差 求速度 float2 velocity = (currentPos.xy - previousPos.xy)/2.0f; // 邻域像素采样,相加求平均 float2 uv = i.uv; float4 c = tex2D(_MainTex, uv); uv += velocity * _BlurSize; for (int it = 1; it < 3; it++, uv += velocity * _BlurSize) { float4 currentColor = tex2D(_MainTex, uv); c += currentColor; } c /= 3; return fixed4(c.rgb, 1.0); } ENDCG Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG }}
阅读全文
0 0
- Unity Shader 学习笔记(23) 运动模糊
- Unity Shader学习笔记:运动模糊
- Unity Shader 学习笔记(21) 模糊、高斯模糊
- shader学习笔记——运动模糊(motion blur)
- Unity Shader学习笔记:模糊效果
- Unity Shader 学习笔记(32) Unity中的Standard Shader
- Unity Shader 学习笔记(1) DrawCall
- Unity Shader 学习笔记(6) 漫反射
- Unity Shader 学习笔记(14) 阴影
- Shader学习笔记(七)Unity Shader Rim示例
- Unity Shader学习笔记(一) shader的基础结构
- Unity Shader 学习笔记(5)第一个简单Shader
- Shader学习笔记(一)认识Unity Shader,Unity Shader的基本结构
- Unity Shader 学习笔记(4)Unity Shader内置变量、函数,Shader Model
- Unity Shader 径向模糊
- Unity shader学习笔记 (四) 分解Shader
- Unity Shader学习笔记:简单的shader
- UNITY SHADER学习笔记1(unity 5.6)
- Java 将图片转二进制再将二进制转成图片
- PHP5i如何连接MySQL数据库和读取数据
- 开通博客 记录点点滴滴
- 浅谈UML学习笔记之构件图和部署图
- quartz实现定时任务
- Unity Shader 学习笔记(23) 运动模糊
- hashcode & equals
- Git merge时遇到的坑
- Spring+Struts2+Hibernate整合开发环境搭建
- vim常用设置
- 简单直接的爬虫,得到所需要的链接地址
- File类的综合应用
- 布局技巧
- 计算进程启动后时长