如何制作公司网站网站怎样做百度推广计划
如何制作公司网站,网站怎样做百度推广计划,了解网站基本知识,网站建设相关知识本系列为作者学习UnityShader入门精要而作的笔记#xff0c;内容将包括#xff1a;
书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更#xff0c;有始无终
我的GitHub仓库
总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 建立一个基… 本系列为作者学习UnityShader入门精要而作的笔记内容将包括
书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更有始无终
我的GitHub仓库
总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 建立一个基本的屏幕后处理脚本系统边缘检测什么是卷积常见的边缘检测算子实现 高斯模糊实现 Bloom效果运动模糊 屏幕后处理效果screen post-processing effects 是游戏中实现屏幕特效的常见方法。Unity使用渲染纹理和脚本实现屏幕后处理效果。
建立一个基本的屏幕后处理脚本系统
屏幕后处理的原理是在渲染完整个场景得到屏幕图像后再对这个图像进行一系列操作实现各种屏幕特效。
想要实现屏幕后处理的基础在于得到渲染后的屏幕图像即抓取屏幕而Unity为我们提供了这一接口——OnRenderImage函数 。它的函数声明如下
Monobehaviour.OnRenderImage(RenderTexture src,RenderTexture dest)
简单易懂的函数当我们再脚本中声明此函数后Unity会把当前渲染得到的图像存储在src源渲染纹理中通过函数中的一系列操作后该函数内操作是我们自定义的再把目标渲染纹理存储在dest渲染纹理中dest最终会被显示到屏幕上。
通常我们使用Graphics.Blit函数 来完成对渲染纹理的处理它有三种函数声明
public static void Blit(Texture src, RenderTexture dest); public static void Blit(Texture src, RenderTexture dest, Material mat, int pass -1); public static void Blit(Texture src, Material mat, int pass -1);
根据函数的定义我们可以看到src对应了源纹理这个参数通常是当前屏幕的渲染纹理或是上一步处理后得到的渲染纹理(RenderTexture是Texture的子类)。dest是目标纹理会直接渲染到屏幕上mat是我们使用的材质这个材质使用的UnityShader会对src画面进行后处理。而Src纹理将会被传递进Shader的_MainTex属性 中也就是说我们直接在Shader中对_MainTex进行处理即可。参数Pass的默认值为-1表示将会依次调用Shader内的所有Pass 否则只会调用给定索引的Pass。
通常情况下OnRenderImage函数会在所有的不透明和透明的Pass执行完毕后被调用以便对场景中的所有游戏对象产生影响。但有时我们希望在不透明的Pass即渲染队列小于等于2500的Pass执行完毕后立即调用OnRenderImage也就是仅仅对不透明物体进行处理可以用onRenderImage函数前添加ImageEffectOpaque属性来实现这样的目的。
实现后处理的效果通常如下
在摄像机中添加一个用于屏幕后处理的脚本在这个脚本中我们会实现OnRenderImage函数来获取当前屏幕的渲染纹理然后再调用Graphic.Blit函数使用特定的UnityShader来对当前图像Texture进行处理再把返回的渲染纹理显示到屏幕上对于一些复杂的屏幕特效我们可能需要多次调用Blit函数来进行多步骤处理。
在进行屏幕后处理之前我们需要检查一系列条件是否满足例如当前平台是否支持渲染纹理和屏幕特效是否支持当前使用的UnityShader等。为此我们创建了一个用于屏幕后处理效果的基类在实现各种屏幕特效时我们只需要继承自该基类再实现派生类中不同的操作即可
Shader
Shader Custom/BrightnessSaturationAndContrast_Copy
{Properties{_MainTex(BaseTexture,2D) white{}_Brightness(Brightness,Float) 1_Saturation(Saturation,Float) 1_Contrast(Contrast,Float) 1}SubShader{Pass{// 该语句是屏幕后处理的标配// 因为屏幕画面应当是最前方的因此深度测试应当总是通过// 关闭背面剔除// 关闭深度写入以防止它覆盖其他物体渲染ZTest AlwaysCull OffZwrite OffCGPROGRAM#pragma fragment frag#pragma vertex vert#include UnityCG.cgincsampler2D _MainTex;float4 _MainTex_ST;float _Brightness;float _Saturation;float _Contrast;struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);o.uv v.texcoord;return o;}fixed4 frag(v2f i):SV_Target{// 亮度 颜色 * 亮度值fixed4 renderTex tex2D(_MainTex,i.uv);fixed3 finalColor renderTex.rgb * _Brightness;// 自定义的饱和度值当饱和度1权值越大的越明显若1则权值越小越明显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);// 对比度颜色值fixed3 avgColor fixed3(0.5,0.5,0.5);finalColor lerp(avgColor,finalColor,_Contrast);return fixed4(finalColor,renderTex.a);}ENDCG}}Fallback Off
}
C#后处理脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;public class CustomBrightnessSaturationAndContrast : CustomPostEffectsBase
{public Shader BriSatConShader;private Material m_briSatConMaterial;public Material BaseMaterial {get {m_briSatConMaterial CheckShaderAndCreateMaterial(BriSatConShader, m_briSatConMaterial);return m_briSatConMaterial;}}[Range(0.0f, 3.0f)]public float brightness 1.0f;[Range(0.0f, 3.0f)]public float saturation 1.0f;[Range(0.0f, 3.0f)]public float contrast 1.0f;override protected void OnRenderImage (RenderTexture source, RenderTexture destination){if (BaseMaterial ! null){BaseMaterial.SetFloat(_Brightness,brightness);BaseMaterial.SetFloat(_Saturation,saturation);BaseMaterial.SetFloat(_Contrast,contrast);Graphics.Blit(source,destination,BaseMaterial);}else{Graphics.Blit(source,destination);}}
}通过对后处理脚本的变量修改我们就可以轻松实现材质面板的变量修改对画面进行后处理 边缘检测
边缘检测的原理是使用边缘检测算子对图像进行卷积convolution 操作至于什么是卷积请看我以往写的一篇文章卷积网络前序——卷积背后的数学原理
什么是卷积 简单的来说使用卷积我们可用以某个像素为中心的周围像素进行权值计算并讲处理后的值重新赋值给中心像素。其中这个由权值构成的矩阵被称为卷积核kenel 。
通过卷积操作我们可以对图像进行一系列的处理如图像模糊边缘检测颜色均值等等操作。
常见的边缘检测算子
让我引用卷积网络前序——卷积背后的数学原理中的一段话来描述为什么边缘检测算子可以实现边缘检测 接下来我们用灰度图来表示要处理的图像因为RGB需要三维向量灰度可以用单个值表示。在灰度图中白色代表1黑色代表0因此我们来看上面这个例子我们可以把矩阵分为三列第一列为正数权值第二列为0第三列为负数权值是第一列的相反数。 因此我们来看上图这个例子明显结果是 1 ∗ ( − 0.25 ) 1 ∗ ( − 0.5 ) 1 ∗ ( − 0.25 ) − 1 1*(-0.25)1*(-0.5)1*(-0.25)-1 1∗(−0.25)1∗(−0.5)1∗(−0.25)−1我们最后的结果用蓝色表示正数红色表示负数。因此最后的卷积结果是一个代表-1的红色格子。 由于这个卷积的矩阵中间列的值是0因此中间列不影响计算它的作用实际上是找出左列和右列灰度值不一样的区块因此实际上功能相当于对图像中所有竖向方向上产生了颜色变化的色块边界进行描边。 这就是边缘检测算子的基本原理本质上来说它的数学原理是基于梯度的所谓边缘指的其实就是左右或上下颜色变化较大的像素点如果将颜色值用函数的数值来表示的话那么就如下图
显然颜色值相差大的部分对应的函数值变化很快而用于描述函数值变化快慢的标准就是函数在该点上的切线角度——也就是函数的梯度因此对于二维函数x,y——即为描述颜色值同时在xy轴上的函数若对其直接求x轴的偏导得到的梯度就代表着颜色值在横向上的变换同理对y轴求偏导代表了在纵向上的变换。 上式其实对应的就是横向的像素值 [ f ( x , y ) , f ( x 1 , y ) ] [f(x,y),f(x1,y)] [f(x,y),f(x1,y)]乘以了矩阵 [ − 1 0 0 1 ] \begin{bmatrix}-1 0\\ 0 1\end{bmatrix} [−1001]。旋转180度后对应的卷积核就是 [ 1 0 0 − 1 ] \begin{bmatrix}1 0\\ 0 -1\end{bmatrix} [100−1]
了解了原理后我们来看看常见的边缘检测算子 这几种常见的边缘检测算子包含了两个方向的卷积核分别用于检测水平和垂直方向上的边缘信息。我们可以单用其中一个卷积核来检测水平或垂直方向上的梯度变换也可以两个合用并计算开方后的均值以横向和纵向两个方位的梯度均值来判定边缘。 实现
后处理脚本
public class CustomEdgeDetection : CustomPostEffectsBase
{public Shader EdgeDectecShader;private Material m_edgeDectecShader;[Range(0.0f, 1.0f)]public float edgesOnly 0.0f;public Color edgeColor Color.black;public Color backgroundColor Color.white;public Material BaseMaterial{get{m_edgeDectecShader CheckShaderAndCreateMaterial(EdgeDectecShader, m_edgeDectecShader);return m_edgeDectecShader;}}override protected void OnRenderImage (RenderTexture source, RenderTexture destination){if (BaseMaterial ! null){BaseMaterial.SetFloat(_EdgeOnly, edgesOnly);BaseMaterial.SetColor(_EdgeColor, edgeColor);BaseMaterial.SetColor(_BackgroundColor, backgroundColor);Graphics.Blit(source,destination,BaseMaterial);}else{Graphics.Blit(source,destination);}}
}
Shader
Shader Custom/EdgeDetectionCopy
{Properties{_MainTex (MainTex, 2D) white {}_EdgeOnly (Edge Only, Float) 1.0_EdgeColor (Edge Color, Color) (0, 0, 0, 1)_BackgroundColor (Background Color, Color) (1, 1, 1, 1)}SubShader{Pass{ZTest AlwaysZWrite OffCull OffCGPROGRAM#pragma fragment frag#pragma vertex vert#include UnityCG.cgincsampler2D _MainTex;// 小坑变量名定义需要使用XXX_TexelSize来访问对应纹理的纹素uniform half4 _MainTex_TexelSize;fixed _EdgeOnly;fixed4 _EdgeColor;fixed4 _BackgroundColor;struct v2f{float4 pos : SV_POSITION;// 该数组用于采样卷积用的像素half2 uv[9] : TEXCOORD0;};v2f vert(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);half2 uv v.texcoord;// 采样卷积中心的周围9个像素点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;}// 计算对比度fixed luminance(fixed4 color){return 0.2125 * color.r 0.7154 * color.g 0.0721 * color.b;}// 应用Sobel卷积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 GradientX 0;half GradientY 0;for (int index 0;index9;index){texColor luminance(tex2D(_MainTex,i.uv[index]));GradientX texColor * Gx[index];GradientY texColor * Gy[index];}half edge 1-abs(GradientX)-abs(GradientY);return edge;}fixed4 frag(v2f i):SV_Target{// 获取边缘(Sobel返回结果越1则越边缘)half edge Sobel(i);//对卷积中心根据卷积值来lerp颜色,edge值越小越接近_EdgeColor,反之越接近原色fixed4 edgeColorMixRigionColor lerp(_EdgeColor,tex2D(_MainTex,i.uv[4]),edge);fixed4 edgeColorMixCustomBGColor lerp(_EdgeColor,_BackgroundColor,edge);return lerp(edgeColorMixRigionColor,edgeColorMixCustomBGColor,_EdgeOnly);}ENDCG}}FallBack Off
}最后的结果可以看到卷积后的图像边缘被我们用黑色进行了描边
高斯模糊
高斯模糊的效果我们在之前的文章中也介绍过了就是用高斯核一个符合高斯分布的卷积核进行计算。
若将卷积核转化为高度图可以看到高斯分布
其中每个元素的计算基于下面的高斯方程 高斯核具有两个特性
距离卷积中心越近的像素影响更大符合高斯分布高斯核越大则模糊程度越大
假设有一张WH像素的图像我们要使用一个NN的高斯核进行卷积那么就要经过NNW*H次计算。高斯核阶数越大计算越复杂。
不过高斯分布本身存在一个性质就是 G ( x , y ) G ( x ) ∗ G ( y ) G(x,y)G(x) * G(y) G(x,y)G(x)∗G(y)(不信可以代入之前的公式验算。之前我在学习机器学习的那节课的时候曾记得两个高斯分布相乘的结果也可以表示为一个高斯分布。
因此该二维的高斯核可以拆分为两个一维的高斯核甚至两个高斯核是对称的甚至整个高斯核还是以中心为对称的我们只需要一个数组就能存储了。
因此相比于直接应用高斯核计算我们可以分为两步先进行横向的一维高斯核计算再进行纵向的一维高斯核计算。 实现
C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CustomGaussianBlur : CustomPostEffectsBase
{public Shader GaussianBlurShader;private Material m_gaussianBlurMaterial;public Material BaseMaterial{get{m_gaussianBlurMaterial CheckShaderAndCreateMaterial(GaussianBlurShader, m_gaussianBlurMaterial);return m_gaussianBlurMaterial;}}[Range(0.2f, 3.0f)]public float BlurSize 0.6f;private RenderTexture buffer0;private RenderTexture buffer1;override protected void OnRenderImage (RenderTexture source, RenderTexture destination){if (BaseMaterial ! null){int rtW source.width;int rtH source.height;BaseMaterial.SetFloat(_BlurSize, BlurSize);// 先渲染到buffer0buffer0 RenderTexture.GetTemporary(rtW, rtH, 0);Graphics.Blit(source, buffer0,BaseMaterial,0);// 再渲染到buffer1buffer1 RenderTexture.GetTemporary(rtW, rtH, 0);Graphics.Blit(buffer0, buffer1, BaseMaterial, 1);// 最后渲染到屏幕Graphics.Blit(buffer1, destination);RenderTexture.ReleaseTemporary(buffer0);RenderTexture.ReleaseTemporary(buffer1);} else {Graphics.Blit(source, destination);}}}
Shader
Shader Custom/GaussianBlur_Copy
{Properties{_MainTex (MainTex, 2D) white {}_BlurSize (Blur Size, Float) 1.0}SubShader{CGINCLUDEsampler2D _MainTex;uniform half4 _MainTex_TexelSize;float _BlurSize;#include UnityCG.cgincstruct v2f{float4 pos : SV_POSITION;half2 uv[5] : TEXCOORD0;};fixed4 CaculateGaussionKenel(v2f i){float weight[3] {0.4026, 0.2442, 0.0545};fixed3 texColor;fixed3 finalColor 0;for (int index 0;index 5;index){texColor tex2D(_MainTex, i.uv[index]);finalColor texColor.rgb * weight[abs(index-2)];}return fixed4(finalColor,1.0);}fixed4 frag(v2f i):SV_Target{fixed4 Blur CaculateGaussionKenel(i);return Blur;}ENDCG// verticalPass{NAME GAUSSIAN_BLUR_VERTICALZTest AlwaysZWrite OffCull OffCGPROGRAM#pragma fragment frag#pragma vertex vertv2f vert(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);half2 uv v.texcoord;o.uv[0] uv _MainTex_TexelSize.xy * half2(0, -2) * _BlurSize;o.uv[1] uv _MainTex_TexelSize.xy * half2(0, -1) * _BlurSize;o.uv[2] uv _MainTex_TexelSize.xy * half2(0, 0) * _BlurSize;o.uv[3] uv _MainTex_TexelSize.xy * half2(0, 1) * _BlurSize;o.uv[4] uv _MainTex_TexelSize.xy * half2(0, 2) * _BlurSize;return o;}ENDCG}// horizonPass{NAME GAUSSIAN_BLUR_HORIZONTALZTest AlwaysZWrite OffCull OffCGPROGRAM#pragma fragment frag#pragma vertex vertv2f vert(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);half2 uv v.texcoord;o.uv[0] uv _MainTex_TexelSize.xy * half2(-2, 0) * _BlurSize;o.uv[1] uv _MainTex_TexelSize.xy * half2(-1, 0) * _BlurSize;o.uv[2] uv _MainTex_TexelSize.xy * half2(0, 0) * _BlurSize;o.uv[3] uv _MainTex_TexelSize.xy * half2(1, 0) * _BlurSize;o.uv[4] uv _MainTex_TexelSize.xy * half2(2, 0) * _BlurSize;return o;}ENDCG}}FallBack Off
} 注意在渲染两个Pass的时候我们不可以直接调用两次Graphics.Blit(source, dest,BaseMaterial,0);Graphics.Blit(source, dest,BaseMaterial,1);因为source是那一帧时屏幕截取的RenderTexture而Dest是目标帧的画面如果按刚才这样写那么就会出现第二次渲染把第一次渲染结果覆盖的情况。
正确的操作是先进行一次渲染然后把上一次的Destination RenderTexture作为下一次渲染的Source。以此类推将最后一次渲染的Dest作为输出结果。
上述代码都是我自己编写的实际上书中的代码要更加全面我这里就暂不贴出一方面书中的代码提供了下采样系数可以手动降采样图像的分辨率减少计算量。另一方面又提供了高斯模糊的迭代代码对图像模糊效果进行多次迭代并使用了buffer0和buffer1两个变量来保存上一次Blit的dest和下一次Blit的src为渲染交替存储RenderTexture。此外提出一点不要把变量定义放在每帧调用的代码中像该例的buffer0和buffer1应当作为全局变量定义。 Bloom效果 Bloom特效简单描述就是让画面中较亮的区域扩散到周围的区域中造成一种朦胧的效果。
根据我们本节的学习你可以想到要如何实现这种效果吗如何使得周围较亮的区域拓展到该区域边缘的像素就需要为这部分像素应用一种卷积这种卷积的效果应当使得该像素的颜色值与周边较亮区域的像素进行混合并且实现模糊。
因此实现思路就是
先提取出图像中较亮部分的像素并将它们存储在一张RenderTexture当中对这些像素进行高斯模糊处理最后将该部分RenderTexture与原图像进行混合得到最终的效果。
上代码其实很简单最关键的找到亮度区域的步骤实际上是将整张图像变暗并与原图进行像素叠加如此一来阈值以下的颜色值归为0阈值以上的被归为亮部。
CS
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CustomBloom : CustomPostEffectsBase
{public Shader BloomShader;private Material m_bloomMaterial;public Material BaseMaterial{get{m_bloomMaterial CheckShaderAndCreateMaterial(BloomShader, m_bloomMaterial);return m_bloomMaterial;}}private RenderTexture buffer0;private RenderTexture buffer1;[Range(0.2f, 3.0f)]public float blurSpread 0.6f;// 判断照明区域的亮度阈值[Range(0.0f, 4.0f)]public float luminanceThreshold 0.6f;override protected void OnRenderImage (RenderTexture source, RenderTexture destination){if (BaseMaterial ! null){BaseMaterial.SetFloat(_LuminanceThreshold, luminanceThreshold);int rtW source.width;int rtH source.height;buffer0 RenderTexture.GetTemporary(rtW, rtH, 0);buffer0.filterMode FilterMode.Bilinear;#region Pass0 : 提取较亮区域// buffer0此时存储亮区Graphics.Blit(source, buffer0, BaseMaterial, 0);#endregion#region Pass1 : 垂直模糊// buffer1此时存储亮区垂直模糊效果BaseMaterial.SetFloat(_BlurSize, 1.0f 1 * blurSpread);buffer1 RenderTexture.GetTemporary(rtW, rtH, 0);Graphics.Blit(buffer0, buffer1, BaseMaterial, 1);RenderTexture.ReleaseTemporary(buffer0);buffer0 buffer1;#endregion#region Pass2 : 水平模糊// buffer1此时存储亮区垂直 水平模糊效果buffer1 RenderTexture.GetTemporary(rtW, rtH, 0);Graphics.Blit(buffer0, buffer1, BaseMaterial, 2);RenderTexture.ReleaseTemporary(buffer0);buffer0 buffer1;#endregion#region Pass3 : 混合两张图像// buffer0为处理后画面并用pass3和原画面混合BaseMaterial.SetTexture (_Bloom, buffer0); Graphics.Blit(source,destination,BaseMaterial,3);RenderTexture.ReleaseTemporary(buffer0);#endregion}else{Graphics.Blit(source,destination);}}
}
Shader
Shader Custom/Bloom_Copy
{Properties{_MainTex (MainTex, 2D) white {}// 由于需要混合两张RenderTexture因此设置两个2DTex_Bloom (Bloom (RGB), 2D) black {}_LuminanceThreshold (Luminance Threshold, Float) 0.5_BlurSize (Blur Size, Float) 1.0}SubShader{CGINCLUDE#include UnityCG.cgincsampler2D _MainTex;half4 _MainTex_TexelSize;sampler2D _Bloom;half4 _Bloom_TexelSize;float _LuminanceThreshold;float _BlurSize;struct v2f{float4 pos : SV_POSITION; half2 uv : TEXCOORD0;};v2f vertGetBright(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);o.uv v.texcoord;return o;}// 计算对比度此处因为物体主体部分是红绿因此希望提高红绿采样的对比度fixed luminance(fixed4 color) {return 0.2125 * color.r 0.7154 * color.g 0.0721 * color.b; }fixed4 fragGetBright(v2f i):SV_Target{fixed4 c tex2D(_MainTex, i.uv);// 获取较亮区域的方法竟然是使得整张图变暗// 减去阈值获取暗度图像阈值以上视为亮部fixed val clamp(c - _LuminanceThreshold, 0.0, 1.0);return c * val;}struct v2fBloom {float4 pos : SV_POSITION;// 存储了两张uv_MainTex和_Bloomhalf4 uv : TEXCOORD0;};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;#endifreturn o; }fixed4 fragBloom(v2fBloom i):SV_Target{// 将暗度图像和原图相加暗色部分接近0叠加后颜色变化小亮色部分接近1叠加后颜色变化大// 因此可以实现亮部突出的效果return tex2D(_MainTex, i.uv.xy) tex2D(_Bloom, i.uv.zw);}ENDCG// 获取较亮区域Pass{CGPROGRAM#pragma vertex vertGetBright#pragma fragment fragGetBrightENDCG}// 高斯模糊UsePass Custom/GaussianBlur_Copy/GAUSSIAN_BLUR_VERTICALUsePass Custom/GaussianBlur_Copy/GAUSSIAN_BLUR_HORIZONTAL// Bloom混合Pass{CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloomENDCG}}Fallback Off
}
同样建议看书中的代码比我写的更规范。 运动模糊
当物体在摄像头内运动的时候会产生运动模糊的视觉效果运动模糊的效果可以让物体运动看起来更加丝滑。最暴力的方法其原理是为一个物体渲染多张连续的图像然后进行混合这意味着需要在同一帧内渲染多次场景。
另一种方法是使用速度缓存在该缓存中存储各个像素当前的运动速度然后用该值来决定模糊的方向和大小显然这种方法更好
书中使用了第一种方法不过不是在一帧内渲染多个场景而是在后处理脚本中保存了之前的渲染结果并不断将当前的渲染图象叠加到之前的渲染图象中。
C#
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CustomMotionBlur : CustomPostEffectsBase
{public Shader MotionBlurShader;private Material m_motionBlurMaterial null;public Material BaseMaterial { get {m_motionBlurMaterial CheckShaderAndCreateMaterial(MotionBlurShader, m_motionBlurMaterial);return m_motionBlurMaterial;} }[Range(0.0f, 0.9f)]public float BlurAmount 0.5f;// 用于保存上一帧渲染结果的RTprivate RenderTexture m_accumulationTexture;//为了在开启后重新叠加图像(避免关闭脚本之前的画面错误叠加)需要摧毁RTprivate void OnDisable(){DestroyImmediate(m_accumulationTexture);}// 检查保存渲染结果的RT是否可用为空且尺寸与画面帧相符bool IsAccumulationTextureAvailable(RenderTexture source){return (m_accumulationTexture null || m_accumulationTexture.width ! source.width || m_accumulationTexture.height ! source.height);}override protected void OnRenderImage (RenderTexture source, RenderTexture destination){if (BaseMaterial ! null){if (IsAccumulationTextureAvailable(source)){// 若不可用则重建RT并渲染DestroyImmediate(m_accumulationTexture);m_accumulationTexture new RenderTexture(source.width, source.height, 0);m_accumulationTexture.hideFlags HideFlags.HideAndDontSave;Graphics.Blit(source, m_accumulationTexture);}//通常在对目标RT再次渲染时需要先清除之前渲染的内容(例如ReleaseTemporary或者DiscardContents)//调用下面函数后则不会对未清除内容的RT再渲染时报错(新版本已弃用该函数)m_accumulationTexture.MarkRestoreExpected();BaseMaterial.SetFloat(_BlurAmount, 1.0f - BlurAmount);// 将当前帧画面和之前累加的画面进行shader处理Graphics.Blit (source, m_accumulationTexture, BaseMaterial);// 最后渲染到目标帧Graphics.Blit (m_accumulationTexture, destination);}else{Graphics.Blit(source,destination);}}}
Shader
Shader Custom/MotionBlur_Copy
{Properties{_MainTex (Albedo (RGB), 2D) white {}_BlurAmount (BlurAmount, Range(0,1)) 0.0}SubShader{CGINCLUDE#include UnityCG.cgincsampler2D _MainTex;half4 _MainTex_TexelSize;fixed _BlurAmount;struct v2f {float4 pos : SV_POSITION;half2 uv : TEXCOORD0;};v2f vert(appdata_img v){v2f o;o.pos UnityObjectToClipPos(v.vertex);o.uv v.texcoord;return o;}// 只需把传入的图像的颜色值直接渲染叠加到当前帧即可// 第二帧会叠加第一帧的颜色值第三帧会叠加第二帧的而第二帧中包含第一帧//假设第一帧叠加到第二帧后透明底0.9则叠加到第三帧后为0.81以此类推直到接近0为止第一帧就完全不显示了// 因此每次叠加就像递归一样_BlurAmount越大运动模糊效果越明显当然不能为1否则直接覆盖了fixed4 fragRGB(v2f i):SV_Target{return fixed4(tex2D(_MainTex,i.uv).rgb,_BlurAmount);}half4 fragA (v2f i) : SV_Target{return tex2D(_MainTex, i.uv);}ENDCGZTest Always Cull Off ZWrite OffPass {Blend SrcAlpha OneMinusSrcAlphaColorMask RGBCGPROGRAM#pragma vertex vert #pragma fragment fragRGB ENDCG}// 处理透明度的Pass看不出有什么影响Pass { Blend One ZeroColorMask ACGPROGRAM #pragma vertex vert #pragma fragment fragAENDCG}}Fallback Off
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87662.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!