(从这里开始可能会记录的更简略一些,时间紧张想迅速读完这本书的主要内容,可能有的部分不会自己上手做)

屏幕后处理通常指渲染完整个场景得到屏幕图像后,再对图像进行操作,抓取屏幕可以使用OnRenderImage(RenderTexture src, RenderTexture dest)将当前渲染的图像存储在 第一个参数对应源渲染纹理中,执行函数中的操作后再进行目标纹理渲染,即第二个参数对应的渲染纹理显示到屏幕上。

通常过程为,在摄像中添加一个用于屏幕后处理的脚本,使用OnRenderImage来信获取当前屏幕的渲染纹理,再调用Graphics.Blit函数使用特定的Shader来对图像处理,再将返回的渲染纹理显示到屏幕上。

原图:

调整亮度、饱和度、对比度

亮度调整:原颜色乘亮度系数得到一个颜色值,再通过每个颜色分量乘一个系数得到亮度值,再使用该亮度创建一个饱和度为0的颜色值,并用该颜色值与上面亮度系数的颜色值以_Saturation进行插值,得到饱和度颜色,最终的颜色为对比度为0的颜色与饱和度颜色以_Contrast属性进行插值的结果。

选中材质并附着shader:

 protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) {if (shader == null) {return null;}if (shader.isSupported && material && material.shader == shader)return material;if (!shader.isSupported) {return null;}else {material = new Material(shader);material.hideFlags = HideFlags.DontSave;if (material)return material;else return null;}}

frag:

fixed4 frag(v2f i) : SV_Target {
fixed4 renderTex = tex2D(_MainTex, i.uv);  // Apply brightness
fixed3 finalColor = renderTex.rgb * _Brightness;// Apply saturation
fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
finalColor = lerp(luminanceColor, finalColor, _Saturation);// Apply contrast
fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
finalColor = lerp(avgColor, finalColor, _Contrast);return fixed4(finalColor, renderTex.a);  }  

边缘检测

原理为应用一些边缘检测算子对图像进行卷积操作,图形学中简化的卷积知识见 games101 lecture6。 卷积操作的效用在于选择不同的卷积核,边缘体现了相邻像素之间存在明显的颜色、亮度、纹理等属性差别,这种差别可以用梯度来表示,边缘处梯度的绝对值比较大。常见的边缘检测算子包含两个方向卷积核分别用于检测水平与竖直,我们对每个像素卷积后的到两个方向上的梯度值,计算整体梯度近似并以此判断边缘。

先放结果:

xxx_TexelSize用于访问纹理对应每个纹素的大小,利用该值计算各个相邻区域的纹理坐标,再vert中计算边缘检测要用的纹理坐标,v2f中定义一个纹理数组(half2 表示二维的16位浮点数)维数为9,得到使用sobel采样时需要的9个纹理坐标。

         v2f vert(appdata_img v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);half2 uv = v.texcoord;o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1);o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0, -1);o.uv[2] = uv + _MainTex_TexelSize.xy * half2(1, -1);o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 0);o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0);o.uv[5] = uv + _MainTex_TexelSize.xy * half2(1, 0);o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1, 1);o.uv[7] = uv + _MainTex_TexelSize.xy * half2(0, 1);o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1);return o;}

片元着色器中实现了调用sobel函数计算每个像素的梯度值edge,并用edge分别计算背景为原图与纯色下的颜色值,利用输入的值边缘度对二者进行插值。下面luminance得到的是按照特定系数乘三个分量得到的亮度颜色,即显示颜色,对其进行卷积操作。

fixed luminance(fixed4 color) {
return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; }half Sobel(v2f i) {const half Gx[9] = {-1,  0,  1,-2,  0,  2,-1,  0,  1};const half Gy[9] = {-1, -2, -1,0,  0,  0,1,  2,  1};      half texColor;half edgeX = 0;half edgeY = 0;for (int it = 0; it < 9; it++) {texColor = luminance(tex2D(_MainTex, i.uv[it]));edgeX += texColor * Gx[it];edgeY += texColor * Gy[it];}half edge = 1 - abs(edgeX) - abs(edgeY);return edge;}

高斯模糊

使用高斯核进行卷积计算,其计算基于高斯方程,标准方差σ一般取1,xy表示当前位置到核中心的整数,计算核中各个位置的高斯核,并对其归一化即让每个权重除以所有权重的和可以保证图像不会变暗。

高斯核维度越高,模糊程度越大,NXN的高斯核对图像卷积滤波,就需要NXNXWXH次采样,n越大 采样次数会更大,把二维的高斯函数拆分为两个一维的高斯函数结果相同,但采样次数变为2xNxWxH,再shader中先后调用两个pass分别两个方向的高斯核滤波。通过图像缩放进一步提高性能,通过改变滤波次数来控制模糊程度。

脚本中调用两次blit,将第一次竖直方向卷积结果存入缓存纹理,再调用blit再缓存纹理基础上进行第二次卷积结果存储显示。

void OnRenderImage (RenderTexture src, RenderTexture dest) {if (material != null) {int rtW = src.width/downSample;int rtH = src.height/downSample;RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);buffer0.filterMode = FilterMode.Bilinear;Graphics.Blit(src, buffer0);for (int i = 0; i < iterations; i++) {material.SetFloat("_BlurSize", 1.0f + i * blurSpread);RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);// Render the vertical passGraphics.Blit(buffer0, buffer1, material, 0);RenderTexture.ReleaseTemporary(buffer0);buffer0 = buffer1;buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);// Render the horizontal passGraphics.Blit(buffer0, buffer1, material, 1);RenderTexture.ReleaseTemporary(buffer0);buffer0 = buffer1;}Graphics.Blit(buffer0, dest);RenderTexture.ReleaseTemporary(buffer0);} else {Graphics.Blit(src, dest);}}

两个pass各自有vert,共用一个frag;在vert中完成。GGINCLUDE与ENDCG语义放于Pass语义块中可以避免需要重复写相同的frag,blursize用于控制采样距离,顶点着色器中做的事情和之前类似,就是将从texcoord得到的中心坐标得到要采样的周围点 存入uv数组中。在顶点着色器中通过uv数组中坐标对应到纹理上的坐标,进行处理。

fixed4 fragBlur(v2f i) : SV_Target {float weight[3] = {0.4026, 0.2442, 0.0545};fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];for (int it = 1; it < 3; it++) {sum += tex2D(_MainTex, i.uv[it*2-1]).rgb * weight[it];sum += tex2D(_MainTex, i.uv[it*2]).rgb * weight[it];}

 Bloom效果

模拟画面中较亮的区域扩散到周围的区域中,造成一种朦胧的效果。

原理:根据一个阈值提取出图像中较亮区域,存储在一张纹理中,对其进行高斯模糊,再与原图像混合。

仍然使用CGINCLUDE与ENDCG组织代码,在提取较亮区域的部分:顶点着色器中只需实现位置变换与纹理获取,在片元着色器中将采样得到的亮度值与阈值相减并控制范围。接着实现混合亮图像与原图像时使用的顶点着色器与片元着色器,在顶点着色器中完成对两个纹理的获得,片元着色器中将其混合。

共用到了四个pass,第一个用于获取较亮区域,第二第三pass用于高斯采样,最后一个用于混合。

获取较亮区域的片元着色器:

fixed4 fragExtractBright(v2f i) : SV_Target {fixed4 c = tex2D(_MainTex, i.uv);fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);return c * val;}

用于混合的顶点片元着色器:

v2fBloom vertBloom(appdata_img v) {v2fBloom o;o.pos = UnityObjectToClipPos (v.vertex);o.uv.xy = v.texcoord;        o.uv.zw = v.texcoord;#if UNITY_UV_STARTS_AT_TOP            if (_MainTex_TexelSize.y < 0.0)o.uv.w = 1.0 - o.uv.w;#endif             return o; }fixed4 fragBloom(v2fBloom i) : SV_Target {return tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom, i.uv.zw);} 

UnityShader入门精要-屏幕后处理效果 亮度饱和度对比度、边缘检测、高斯模糊、bloom效果、运动模糊相关推荐

  1. [学习笔记]UnityShader入门精要_第12章_屏幕后处理效果

    12.2 调整屏幕的亮度,饱和度和对比度 C# CheckShaderAndCreateMaterial Range OnRenderImage Material.SetFloat Graphics ...

  2. UnityShader入门精要-渲染纹理 镜子 玻璃 效果

    通常模式是一个摄像机的渲染结果输出到颜色缓冲内并显示到屏幕上,现代GPU允许我们把场景渲染到一个中间缓冲(渲染目标纹理RTT),与之相关的是多重渲染目标MRT允许我们把场景同时渲染到多个渲染目标中而不 ...

  3. UnityShader入门精要-透明效果

    实现透明效果的方法:1.透明度测试2.透明度混合 深度缓冲Z-buffer决定了哪个物体的那些部分会被渲染在前面,而哪些部分会被遮挡(比较距照相机的距离),渲染一个片元时需要把他的深度值与已经存在在深 ...

  4. 《UnityShader入门精要》总结(1)理论篇

    紫色:大类概念或简短有力的总结 蓝色:细分概念或重要部分 红色:重要的补充注释 第二章:渲染流程与流程分工 渲染的流程分三个阶段: 应用阶段(开发者控制阶段) 由开发者全权进行管理,控制场景内摄像机位 ...

  5. UnityShader入门精要——运动模糊

    运动模糊是真实世界中的摄像机的一种效果.如果在摄像机曝光时,拍摄场景发生了变化,就会产生模糊的画面. 运动模糊的实现有多种方法.一种实现方法是利用一块累积缓存(accumulation buffer ...

  6. UnityShader入门精要——运动模糊(2)

    本次利用速度映射图方法实现运动模糊.速度映射图中存储了每个像素的速度,然后使用这个速度来决定模糊的方向和大小. 速度缓冲生成的方法: (1)把场景中所有物体的速度渲染到一张纹理中.但这种方法的缺点在于 ...

  7. UnityShader入门精要-9

    目录 1. Unity的渲染路径 前向渲染路径 Unity中的前向渲染 延迟渲染 Unity的光源类型 Unity的光照衰减 Unity的阴影 1. Unity的渲染路径 Unity 5.0之前,有3 ...

  8. UnityShader入门精要——全局雾效

    基于屏幕后处理的全局雾效的关键是,根据深度纹理来重建每个像素在世界空间下的位置.我们在模拟运动模糊时已经实现了这个要求,即构建出当前像素的NDC坐标,再通过当前摄像机的视角*投影矩阵的逆矩阵来得到世界 ...

  9. [UnityShader入门精要读书笔记]37.水波效果

    在这里,使用一张立方体纹理(cubemap)作为环境纹理,模拟反射.为了模拟折射效果,我们使用GrabPass来获取当前屏幕的渲染纹理,并使用切线空间下的法线方向对像素的屏幕坐标进行偏移,再使用该坐标 ...

最新文章

  1. 011_TreeMap对键实现了Comparable接口的对象排序
  2. 传统与敏捷开发的真正区别
  3. 哈·曼丁的故事(三)
  4. 介绍一个 Windows 10 资源管理器的替代工具 - Explorer++
  5. Neo4j:动态添加属性/设置动态属性
  6. thinkphp5 判断数据是否存在_ThinkPHP 5.1 中间件中判断要访问的操作是否存在
  7. Aruba发布业界首款服务智能边缘的云原生平台Aruba ESP
  8. 大项目之网上书城(十二)——完成啦
  9. 20179311《网络攻防实践》第五周作业
  10. 一个优秀的 Node.js 开发者
  11. PostgreSQL(2)常用命令(附教程)
  12. 西门子plc语句表是c语言吗,三菱、西门子PLC常用语句表,速来收!
  13. php公众号支付开发,微信公众号支付开发
  14. 数据可视化实战案例分享
  15. 基于django的视频点播网站开发-step15-项目部署 1
  16. Rayman的绝顶之路——Leetcode每日一题打卡13
  17. 史上最容易听错的歌词
  18. 新时达系统服务器怎么看故障,新时达系统故障详解:38故障
  19. iOS 直播 IJKPlayer
  20. 安装gfortran

热门文章

  1. 华为链路聚合手工负载分担和 lacp 模式
  2. 如何协助企业IT架构转型
  3. LAIC2022之犯罪事实实体识别(基于飞桨UIE+半监督)
  4. 京东首页html+css1.0
  5. ios调用restful接口_Office 365 iOS SDK-如何调用SharePoint REST API
  6. PDF文件不能编辑,有什么办法能够解决?
  7. dataframe 按条件筛选行
  8. JSON的正确格式及JSON与实体类相互转换
  9. linux trace 进程 文件路径,linux panic 问题定位
  10. 用U盘制作win7系统安装盘