12.屏幕高斯模糊

本系列文章由@浅墨_毛星云 出品,转载请注明出处。  
文章链接: http://blog.csdn.net/poem_qianmo/article/details/51871531
作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442
本文工程使用的Unity3D版本: 5.2.1 


一、降采样与高斯模糊的原理


 

首先梳理一下在Unity中实现高斯模糊效果需用到的几个图像处理的知识点,说起来也很巧,正好和之前我写过一个关于OpenCV的系列博客里的这篇文章(http://blog.csdn.net/poem_qianmo/article/details/22745559)涉及的知识点类似。

 

 



1.1 关于图像的降采样

 


降采样(Downsample)也称下采样(Subsample),按字面意思理解即是降低采样频率。对于一幅N*M的图像来说,如果降采样系数为k,则降采样即是在原图中每行每列每隔k个点取一个点组成一幅图像的一个过程。

不难得出,降采样系数K值越大,则需要处理的像素点越少,运行速度越快。




1.2 高斯模糊的原理

 


高斯模糊(Gaussian Blur),也叫高斯平滑,高斯滤波,其通常用它来减少图像噪声以及降低细节层次,常常也被用于对图像进行模糊。

通俗的讲,高斯模糊就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯模糊的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

高斯分布的数学表示如下:

其中,x为到像素中心的距离,σ为标准差。

 

 

高斯分布(正态分布曲线)

分条来说明一下高斯模糊的几个要点:

  • 从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。
  • 由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。
  • 高斯模糊能够把某一点周围的像素色值按高斯曲线统计起来,采用数学上加权平均的计算方法得到这条曲线的色值
  • 所谓"模糊",可以理解成每一个像素都取周边像素的平均值。
  • 图像与圆形方框模糊做卷积将会生成更加精确的焦外成像效果。由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。

高斯模糊的原理大致如此。若各位还想进一步了解,可以参考高斯模糊的wiki,以及《Real-Time Rendering 3rd》,或各种图像处理的书籍。相关参考内容见附录中的reference。

下面主要来一起看一下高斯模糊特效在Unity中的实现。


 




二、高斯模糊特效在Unity中的实现





Unity中的屏幕特效,通常分为两部分来实现:

    • Shader代码实现部分
    • C#/javascript代码实现部分

 上述两者结合起来,便可以在Unity中实现具有很强可控性和灵活性的屏幕后期特效。

下面即是从这两个方面对高斯模糊的特效进行实现。其实现思路类似Standard Assets/Image Effect中的Blur,但是本文的实现更简洁,有更大的可控性。

 

 


2.1 Shader代码部分



本次的高斯模糊Shader包含逐行注释后约200多行。

书写思路方面,采用了3个通道(Pass)各司其职,他们分别是:

  • 通道0:降采样通道。
  • 通道1:垂直方向模糊处理通道。
  • 通道2:水平方向模糊处理通道。

而三个通道中共用的变量、函数和结构体的代码位于CGINCLUDE和ENDCG之间。

以下贴出经过详细注释的Shader源码:

 

[cpp] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. Shader "Learning Unity Shader/Lecture 15/RapidBlurEffect"  
  2. {  
  3.     //-----------------------------------【属性 || Properties】------------------------------------------    
  4.     Properties  
  5.     {  
  6.         //主纹理  
  7.         _MainTex("Base (RGB)", 2D) = "white" {}  
  8.     }  
  9.   
  10.     //----------------------------------【子着色器 || SubShader】---------------------------------------    
  11.     SubShader  
  12.     {  
  13.         ZWrite Off  
  14.         Blend Off  
  15.   
  16.         //---------------------------------------【通道0 || Pass 0】------------------------------------  
  17.         //通道0:降采样通道 ||Pass 0: Down Sample Pass  
  18.         Pass  
  19.         {  
  20.             ZTest Off  
  21.             Cull Off  
  22.   
  23.             CGPROGRAM  
  24.   
  25.             //指定此通道的顶点着色器为vert_DownSmpl  
  26.             #pragma vertex vert_DownSmpl  
  27.             //指定此通道的像素着色器为frag_DownSmpl  
  28.             #pragma fragment frag_DownSmpl  
  29.   
  30.             ENDCG  
  31.   
  32.         }  
  33.   
  34.         //---------------------------------------【通道1 || Pass 1】------------------------------------  
  35.         //通道1:垂直方向模糊处理通道 ||Pass 1: Vertical Pass  
  36.         Pass  
  37.         {  
  38.             ZTest Always  
  39.             Cull Off  
  40.   
  41.             CGPROGRAM  
  42.   
  43.             //指定此通道的顶点着色器为vert_BlurVertical  
  44.             #pragma vertex vert_BlurVertical  
  45.             //指定此通道的像素着色器为frag_Blur  
  46.             #pragma fragment frag_Blur  
  47.   
  48.             ENDCG  
  49.         }  
  50.   
  51.         //---------------------------------------【通道2 || Pass 2】------------------------------------  
  52.         //通道2:水平方向模糊处理通道 ||Pass 2: Horizontal Pass  
  53.         Pass  
  54.         {  
  55.             ZTest Always  
  56.             Cull Off  
  57.   
  58.             CGPROGRAM  
  59.   
  60.             //指定此通道的顶点着色器为vert_BlurHorizontal  
  61.             #pragma vertex vert_BlurHorizontal  
  62.             //指定此通道的像素着色器为frag_Blur  
  63.             #pragma fragment frag_Blur  
  64.   
  65.             ENDCG  
  66.         }  
  67.     }  
  68.   
  69.   
  70.     //-------------------------CG着色语言声明部分 || Begin CG Include Part----------------------    
  71.     CGINCLUDE  
  72.   
  73.     //【1】头文件包含 || include  
  74.     #include "UnityCG.cginc"  
  75.   
  76.     //【2】变量声明 || Variable Declaration  
  77.     sampler2D _MainTex;  
  78.     //UnityCG.cginc中内置的变量,纹理中的单像素尺寸|| it is the size of a texel of the texture  
  79.     uniform half4 _MainTex_TexelSize;  
  80.     //C#脚本控制的变量 || Parameter  
  81.     uniform half _DownSampleValue;  
  82.   
  83.     //【3】顶点输入结构体 || Vertex Input Struct  
  84.     struct VertexInput  
  85.     {  
  86.         //顶点位置坐标  
  87.         float4 vertex : POSITION;  
  88.         //一级纹理坐标  
  89.         half2 texcoord : TEXCOORD0;  
  90.     };  
  91.   
  92.     //【4】降采样输出结构体 || Vertex Input Struct  
  93.     struct VertexOutput_DownSmpl  
  94.     {  
  95.         //像素位置坐标  
  96.         float4 pos : SV_POSITION;  
  97.         //一级纹理坐标(右上)  
  98.         half2 uv20 : TEXCOORD0;  
  99.         //二级纹理坐标(左下)  
  100.         half2 uv21 : TEXCOORD1;  
  101.         //三级纹理坐标(右下)  
  102.         half2 uv22 : TEXCOORD2;  
  103.         //四级纹理坐标(左上)  
  104.         half2 uv23 : TEXCOORD3;  
  105.     };  
  106.   
  107.   
  108.     //【5】准备高斯模糊权重矩阵参数7x4的矩阵 ||  Gauss Weight  
  109.     static const half4 GaussWeight[7] =  
  110.     {  
  111.         half4(0.0205,0.0205,0.0205,0),  
  112.         half4(0.0855,0.0855,0.0855,0),  
  113.         half4(0.232,0.232,0.232,0),  
  114.         half4(0.324,0.324,0.324,1),  
  115.         half4(0.232,0.232,0.232,0),  
  116.         half4(0.0855,0.0855,0.0855,0),  
  117.         half4(0.0205,0.0205,0.0205,0)  
  118.     };  
  119.   
  120.   
  121.     //【6】顶点着色函数 || Vertex Shader Function  
  122.     VertexOutput_DownSmpl vert_DownSmpl(VertexInput v)  
  123.     {  
  124.         //【6.1】实例化一个降采样输出结构  
  125.         VertexOutput_DownSmpl o;  
  126.   
  127.         //【6.2】填充输出结构  
  128.         //将三维空间中的坐标投影到二维窗口    
  129.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  130.         //对图像的降采样:取像素上下左右周围的点,分别存于四级纹理坐标中  
  131.         o.uv20 = v.texcoord + _MainTex_TexelSize.xy* half2(0.5h, 0.5h);;  
  132.         o.uv21 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, -0.5h);  
  133.         o.uv22 = v.texcoord + _MainTex_TexelSize.xy * half2(0.5h, -0.5h);  
  134.         o.uv23 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, 0.5h);  
  135.   
  136.         //【6.3】返回最终的输出结果  
  137.         return o;  
  138.     }  
  139.   
  140.     //【7】片段着色函数 || Fragment Shader Function  
  141.     fixed4 frag_DownSmpl(VertexOutput_DownSmpl i) : SV_Target  
  142.     {  
  143.         //【7.1】定义一个临时的颜色值  
  144.         fixed4 color = (0,0,0,0);  
  145.   
  146.         //【7.2】四个相邻像素点处的纹理值相加  
  147.         color += tex2D(_MainTex, i.uv20);  
  148.         color += tex2D(_MainTex, i.uv21);  
  149.         color += tex2D(_MainTex, i.uv22);  
  150.         color += tex2D(_MainTex, i.uv23);  
  151.   
  152.         //【7.3】返回最终的平均值  
  153.         return color / 4;  
  154.     }  
  155.   
  156.     //【8】顶点输入结构体 || Vertex Input Struct  
  157.     struct VertexOutput_Blur  
  158.     {  
  159.         //像素坐标  
  160.         float4 pos : SV_POSITION;  
  161.         //一级纹理(纹理坐标)  
  162.         half4 uv : TEXCOORD0;  
  163.         //二级纹理(偏移量)  
  164.         half2 offset : TEXCOORD1;  
  165.     };  
  166.   
  167.     //【9】顶点着色函数 || Vertex Shader Function  
  168.     VertexOutput_Blur vert_BlurHorizontal(VertexInput v)  
  169.     {  
  170.         //【9.1】实例化一个输出结构  
  171.         VertexOutput_Blur o;  
  172.   
  173.         //【9.2】填充输出结构  
  174.         //将三维空间中的坐标投影到二维窗口    
  175.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  176.         //纹理坐标  
  177.         o.uv = half4(v.texcoord.xy, 1, 1);  
  178.         //计算X方向的偏移量  
  179.         o.offset = _MainTex_TexelSize.xy * half2(1.0, 0.0) * _DownSampleValue;  
  180.   
  181.         //【9.3】返回最终的输出结果  
  182.         return o;  
  183.     }  
  184.   
  185.     //【10】顶点着色函数 || Vertex Shader Function  
  186.     VertexOutput_Blur vert_BlurVertical(VertexInput v)  
  187.     {  
  188.         //【10.1】实例化一个输出结构  
  189.         VertexOutput_Blur o;  
  190.   
  191.         //【10.2】填充输出结构  
  192.         //将三维空间中的坐标投影到二维窗口    
  193.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  194.         //纹理坐标  
  195.         o.uv = half4(v.texcoord.xy, 1, 1);  
  196.         //计算Y方向的偏移量  
  197.         o.offset = _MainTex_TexelSize.xy * half2(0.0, 1.0) * _DownSampleValue;  
  198.   
  199.         //【10.3】返回最终的输出结果  
  200.         return o;  
  201.     }  
  202.   
  203.     //【11】片段着色函数 || Fragment Shader Function  
  204.     half4 frag_Blur(VertexOutput_Blur i) : SV_Target  
  205.     {  
  206.         //【11.1】获取原始的uv坐标  
  207.         half2 uv = i.uv.xy;  
  208.   
  209.         //【11.2】获取偏移量  
  210.         half2 OffsetWidth = i.offset;  
  211.         //从中心点偏移3个间隔,从最左或最上开始加权累加  
  212.         half2 uv_withOffset = uv - OffsetWidth * 3.0;  
  213.   
  214.         //【11.3】循环获取加权后的颜色值  
  215.         half4 color = 0;  
  216.         for (int j = 0; j< 7; j++)  
  217.         {  
  218.             //偏移后的像素纹理值  
  219.             half4 texCol = tex2D(_MainTex, uv_withOffset);  
  220.             //待输出颜色值+=偏移后的像素纹理值 x 高斯权重  
  221.             color += texCol * GaussWeight[j];  
  222.             //移到下一个像素处,准备下一次循环加权  
  223.             uv_withOffset += OffsetWidth;  
  224.         }  
  225.   
  226.         //【11.4】返回最终的颜色值  
  227.         return color;  
  228.     }  
  229.   
  230.     //-------------------结束CG着色语言声明部分  || End CG Programming Part------------------               
  231.     ENDCG  
  232.   
  233.     FallBack Off  
  234. }  





2.2 C#代码部分



C#脚本文件的代码可以从我们之前的几篇分析屏幕特效实现的文章中重用(如这篇实现屏幕油画特效的文章:http://blog.csdn.net/poem_qianmo/article/details/49719247),只用稍微改一点细节即可。 

贴出详细注释的配合Shader实现此特效的C#脚本:

[cpp] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. //设置在编辑模式下也执行该脚本  
  5. [ExecuteInEditMode]  
  6. //添加选项到菜单中  
  7. [AddComponentMenu("Learning Unity Shader/Lecture 15/RapidBlurEffect")]  
  8. public class RapidBlurEffect : MonoBehaviour  
  9. {  
  10.     //-------------------变量声明部分-------------------  
  11.     #region Variables  
  12.       
  13.     //指定Shader名称  
  14.     private string ShaderName = "Learning Unity Shader/Lecture 15/RapidBlurEffect";  
  15.   
  16.     //着色器和材质实例  
  17.     public Shader CurShader;  
  18.     private Material CurMaterial;  
  19.   
  20.     //几个用于调节参数的中间变量  
  21.     public static int ChangeValue;  
  22.     public static float ChangeValue2;  
  23.     public static int ChangeValue3;  
  24.   
  25.     //降采样次数  
  26.     [Range(0, 6), Tooltip("[降采样次数]向下采样的次数。此值越大,则采样间隔越大,需要处理的像素点越少,运行速度越快。")]  
  27.     public int DownSampleNum = 2;  
  28.     //模糊扩散度  
  29.     [Range(0.0f, 20.0f), Tooltip("[模糊扩散度]进行高斯模糊时,相邻像素点的间隔。此值越大相邻像素间隔越远,图像越模糊。但过大的值会导致失真。")]  
  30.     public float BlurSpreadSize = 3.0f;  
  31.     //迭代次数  
  32.     [Range(0, 8), Tooltip("[迭代次数]此值越大,则模糊操作的迭代次数越多,模糊效果越好,但消耗越大。")]  
  33.     public int BlurIterations = 3;  
  34.   
  35.     #endregion  
  36.   
  37.     //-------------------------材质的get&set----------------------------  
  38.     #region MaterialGetAndSet  
  39.     Material material  
  40.     {  
  41.         get  
  42.         {  
  43.             if (CurMaterial == null)  
  44.             {  
  45.                 CurMaterial = new Material(CurShader);  
  46.                 CurMaterial.hideFlags = HideFlags.HideAndDontSave;  
  47.             }  
  48.             return CurMaterial;  
  49.         }  
  50.     }  
  51.     #endregion  
  52.   
  53.     #region Functions  
  54.     //-----------------------------------------【Start()函数】---------------------------------------------    
  55.     // 说明:此函数仅在Update函数第一次被调用前被调用  
  56.     //--------------------------------------------------------------------------------------------------------  
  57.     void Start()  
  58.     {  
  59.         //依次赋值  
  60.         ChangeValue = DownSampleNum;  
  61.         ChangeValue2 = BlurSpreadSize;  
  62.         ChangeValue3 = BlurIterations;  
  63.   
  64.         //找到当前的Shader文件  
  65.         CurShader = Shader.Find(ShaderName);  
  66.   
  67.         //判断当前设备是否支持屏幕特效  
  68.         if (!SystemInfo.supportsImageEffects)  
  69.         {  
  70.             enabled = false;  
  71.             return;  
  72.         }  
  73.     }  
  74.   
  75.     //-------------------------------------【OnRenderImage()函数】------------------------------------    
  76.     // 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果  
  77.     //--------------------------------------------------------------------------------------------------------  
  78.     void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)  
  79.     {  
  80.         //着色器实例不为空,就进行参数设置  
  81.         if (CurShader != null)  
  82.         {  
  83.             //【0】参数准备  
  84.             //根据向下采样的次数确定宽度系数。用于控制降采样后相邻像素的间隔  
  85.             float widthMod = 1.0f / (1.0f * (1 << DownSampleNum));  
  86.             //Shader的降采样参数赋值  
  87.             material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod);  
  88.             //设置渲染模式:双线性  
  89.             sourceTexture.filterMode = FilterMode.Bilinear;  
  90.             //通过右移,准备长、宽参数值  
  91.             int renderWidth = sourceTexture.width >> DownSampleNum;  
  92.             int renderHeight = sourceTexture.height >> DownSampleNum;  
  93.   
  94.             // 【1】处理Shader的通道0,用于降采样 ||Pass 0,for down sample  
  95.             //准备一个缓存renderBuffer,用于准备存放最终数据  
  96.             RenderTexture renderBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);  
  97.             //设置渲染模式:双线性  
  98.             renderBuffer.filterMode = FilterMode.Bilinear;  
  99.             //拷贝sourceTexture中的渲染数据到renderBuffer,并仅绘制指定的pass0的纹理数据  
  100.             Graphics.Blit(sourceTexture, renderBuffer, material, 0);  
  101.   
  102.             //【2】根据BlurIterations(迭代次数),来进行指定次数的迭代操作  
  103.             for (int i = 0; i < BlurIterations; i++)  
  104.             {  
  105.                 //【2.1】Shader参数赋值  
  106.                 //迭代偏移量参数  
  107.                 float iterationOffs = (i * 1.0f);  
  108.                 //Shader的降采样参数赋值  
  109.                 material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod + iterationOffs);  
  110.   
  111.                 // 【2.2】处理Shader的通道1,垂直方向模糊处理 || Pass1,for vertical blur  
  112.                 // 定义一个临时渲染的缓存tempBuffer  
  113.                 RenderTexture tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);  
  114.                 // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass1的纹理数据  
  115.                 Graphics.Blit(renderBuffer, tempBuffer, material, 1);  
  116.                 //  清空renderBuffer  
  117.                 RenderTexture.ReleaseTemporary(renderBuffer);  
  118.                 // 将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0和pass1的数据已经准备好  
  119.                  renderBuffer = tempBuffer;  
  120.   
  121.                 // 【2.3】处理Shader的通道2,竖直方向模糊处理 || Pass2,for horizontal blur  
  122.                 // 获取临时渲染纹理  
  123.                 tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);  
  124.                 // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass2的纹理数据  
  125.                 Graphics.Blit(renderBuffer, tempBuffer, CurMaterial, 2);  
  126.   
  127.                 //【2.4】得到pass0、pass1和pass2的数据都已经准备好的renderBuffer  
  128.                 // 再次清空renderBuffer  
  129.                 RenderTexture.ReleaseTemporary(renderBuffer);  
  130.                 // 再次将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0、pass1和pass2的数据都已经准备好  
  131.                 renderBuffer = tempBuffer;  
  132.             }  
  133.   
  134.             //拷贝最终的renderBuffer到目标纹理,并绘制所有通道的纹理到屏幕  
  135.             Graphics.Blit(renderBuffer, destTexture);  
  136.             //清空renderBuffer  
  137.             RenderTexture.ReleaseTemporary(renderBuffer);  
  138.   
  139.         }  
  140.   
  141.         //着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的  
  142.         else  
  143.         {  
  144.             //直接拷贝源纹理到目标渲染纹理  
  145.             Graphics.Blit(sourceTexture, destTexture);  
  146.         }  
  147.     }  
  148.   
  149.   
  150.     //-----------------------------------------【OnValidate()函数】--------------------------------------    
  151.     // 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用  
  152.     //--------------------------------------------------------------------------------------------------------  
  153.     void OnValidate()  
  154.     {  
  155.         //将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效  
  156.         ChangeValue = DownSampleNum;  
  157.         ChangeValue2 = BlurSpreadSize;  
  158.         ChangeValue3 = BlurIterations;  
  159.     }  
  160.   
  161.     //-----------------------------------------【Update()函数】--------------------------------------    
  162.     // 说明:此函数每帧都会被调用  
  163.     //--------------------------------------------------------------------------------------------------------  
  164.     void Update()  
  165.     {  
  166.         //若程序在运行,进行赋值  
  167.         if (Application.isPlaying)  
  168.         {  
  169.             //赋值  
  170.             DownSampleNum = ChangeValue;  
  171.             BlurSpreadSize = ChangeValue2;  
  172.             BlurIterations = ChangeValue3;  
  173.         }  
  174.         //若程序没有在运行,去寻找对应的Shader文件  
  175. #if UNITY_EDITOR  
  176.         if (Application.isPlaying != true)  
  177.         {  
  178.             CurShader = Shader.Find(ShaderName);  
  179.         }  
  180. #endif  
  181.   
  182.     }  
  183.   
  184.     //-----------------------------------------【OnDisable()函数】---------------------------------------    
  185.     // 说明:当对象变为不可用或非激活状态时此函数便被调用    
  186.     //--------------------------------------------------------------------------------------------------------  
  187.     void OnDisable()  
  188.     {  
  189.         if (CurMaterial)  
  190.         {  
  191.             //立即销毁材质实例  
  192.             DestroyImmediate(CurMaterial);  
  193.         }  
  194.   
  195.     }  
  196.   
  197.  #endregion  
  198.   
  199. }  


将此C#代码拖拽到场景的主摄像机之上, 且你的工程中也存在2.1节中贴出的Shader代码,那么就可以在Game窗口中看到经过了屏幕模糊特效的处理后的镜头效果。

 

而Inspector中可得到如下所示的脚本选项。

 

其中,有3个选项可以调节,他们分别是:

  • [Down Sample Num] – 降采样的次数。此值越大,则采样间隔越大,需要处理的像素点越少,运行速度越快。
  • [Blur Speread Size] -模糊扩散度。进行高斯模糊时,相邻像素点的间隔。此值越大相邻像素间隔越远,图像越模糊。但过大的值会导致失真。
  • [Blur Iterations] -迭代次数。此值越大,则模糊操作的迭代次数越多,模糊效果越好,但消耗越大。

调节这三个参数,便可以在场景中定制出自己需要的模糊特效。

 




2.3 推荐几组参数设置



这边推荐几组效果出色较为出色的参数预设,方便有需要的朋友定制出适合自己的效果。

 





 




 


 


三、最终实现的效果图示




3.1 Low Poly风格的效果测试



 







3.2 卡通风格效果测试


 


 


 

 


3.3 写实风格的效果测试


 

 




 

 

 

附1、本文配套源码下载链接


  【Github】本文Shader源码

 


附2、Reference

 

[1] https://en.wikipedia.org/wiki/Gaussian_blur

[2] http://www.cnblogs.com/foxianmo/p/4931507.html

[3]《Real-Time Rendering 3rd》,p467-p473.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广东东软学院计算机系主任罗,广东东软学院副校长朱爱红一行来访我校

3月27日&#xff0c;广东东软学院副校长朱爱红、教务部部长程江涛、品牌发展部部长李惠旋、计算机学院院长黄迅、SOVO主任吴志成、网络与信息中心主任付冬波、实验教学中心主任谢振华、图书馆馆长刘春林等一行18人来访我校。我校副校长郭权接待来访嘉宾。嘉宾一行参加调研会议嘉…

事业单位职称工资计算机,终于!事业单位绩效工资、职称变了!关系上千万人收入!...

原标题&#xff1a;终于&#xff01;事业单位绩效工资、职称变了&#xff01;关系上千万人收入&#xff01;大学生热烈追捧事业单位和公务员&#xff0c;并将其称为铁饭碗&#xff01;有很多大学生们在大学毕业之后就选择了去考公务员或者事业单位&#xff01;甚至不少同学甚至…

remove是什么意思计算机语言,remove是什么意思?remove是什么意思?

remove()是C语言中的函数&#xff0c;一般作用是删除数组、链表对象所有的元素。函数原型是intremove(char*filename)。函数功能remove()函数用于删除指定的文件&#xff0c;其原型如下&#xff1a;int remove(char *filename);函数声明2&#xff1a;templateinline bool remov…

Unity3D_NGUI_安卓APK安装包瘦身实践

减包瘦身是个精细活。本文整理了0907版本操作过程&#xff0c;以备日后参考。 经过一番折腾&#xff0c;各位攻城狮的努力&#xff0c;美术设计师的支持&#xff0c;策划爷的理解&#xff0c;UI资源&#xff08;图集、字体、单局外模型贴图&#xff09;从45.4MB减少到24.5MB。如…

Unity3D之Shader自定义编辑器功能拓展

一、前言最近在开发一个关卡类的游戏&#xff0c;在导入一些3D物体的时候&#xff0c;发现很多时候同一个3D物体需要渲染的方式不一样&#xff0c;比如这颗树要双面渲染&#xff08;Cull Off&#xff09;&#xff0c;但在很多情况下是可以剔除背面&#xff08;Cull Back&#x…

理解依赖注入(IOC)

IOC:英文全称&#xff1a;Inversion of Control&#xff0c;中文名称&#xff1a;控制反转&#xff0c;它还有个名字叫依赖注入&#xff08;Dependency Injection&#xff09;。 作用&#xff1a;将各层的对象以松耦合的方式组织在一起&#xff0c;解耦&#xff0c;各层对象的调…

局域网win7计算机如何互访,局域网win7电脑的互访步骤

局域网win7电脑的互访步骤Windows7如何实现局域网内的互访?下面是局域网win7电脑互访的步骤&#xff0c;为大家提供参考。步骤一&#xff1a;同步工作组 不管使用的是什么版本的Windows操作系统&#xff0c;第一步&#xff0c;要保证联网的各计算机的工作组名称一致步骤二&…

服务器自动挂载硬盘,Linux硬盘分区及开机自动挂载

本文以CentOS 6.4为例&#xff0c;查看当前linux服务器分区&#xff1a;df -h查看当前linux服务器硬盘&#xff1a;fdisk -l/dev/sda 第一块硬盘/dev/sdb 第二块硬盘依此类推以/dev/sdb为新增硬盘为例&#xff0c;需要进行以下操作方可正常使用1、分区fdisk /dev/sdb依次输入n&…

GPU Pro2 - 1.Terrain and Ocean Rendering with Hardware Tessellation

最近时间多了起来&#xff0c;准备捡起扔下了的渲染部分的知识。想拜读下GPU Pro系列并且做个笔记&#xff0c;不知道自己能否坚持下来&#xff0c;但愿可以吧。自己能力也有限&#xff0c;写的东西也只是自己的理解&#xff0c;肯定有很多理解不到位甚至错误的地方&#xff0c…

GPU Pro2 - 3.Procedural Content Generation on the GPU

GPU Pro2 - 3.Procedural Content Generation on the GPU 这篇文章着重介绍了基于Brownian 噪声和高度图在GPU中实时生成和渲染无限大地形系统。 Procedural content generation (PCG)程序化生成在许多游戏中已经有广泛应用&#xff0c;从简单的随机物体摆放&#xff0c;到全…

GPU Gems1 - 1 用物理模型进行高效的水模拟(Effective Water Simulation from Physical Models)

该读书笔记大多内容参照了大神浅墨的该篇文章https://zhuanlan.zhihu.com/p/35974789 本章介绍了一种在GPU中模拟和渲染大的水体的系统。它把基本网格的集合波动于动态发现贴图的生成结合起来。 1.1 目标和范围 这章里&#xff0c;我们将由计算简单正弦函数之和开始&#xf…

GPU Gems1 - 2 水刻蚀的渲染

2.1 引言 光线从弯曲的表面反射或折射&#xff0c;因此只聚焦在受光面上的某些区域&#xff0c;于是就产生了刻蚀现象。本文从美学角度出发&#xff0c;不以纯物理的方式计算&#xff0c;使其很容易在大多数图形硬件上实现&#xff0c;效果又十分逼真。 2.2 刻蚀的计算 如果想…

邮箱服务器ip地址白名单,申请SSL证书时如何设置IP地址白名单和邮箱白名单

8月3日消息 在申请SSL证书时&#xff0c;由于您的邮箱可能默认设置或自定义设置了拦截国外邮件&#xff0c;可能会导致您接收不到CA的邮件&#xff0c;给验证、收取证书带来了不便&#xff1b;如果服务器&#xff0c;防火墙也设置了拦截操作&#xff0c;那么即使您按CA要求完成…

GPU Gems1 - 3 Dawn Demo中的皮肤渲染(Skin in the Dawn Demo)

该篇文章参照浅墨的这篇文章&#xff1a;https://zhuanlan.zhihu.com/p/35974789 Dawn是由NVIDIA创建的&#xff0c;用来介绍GeForce FX产品线的演示程序&#xff0c;它说明如何使用可编程的着色技术创建出逼真的人类角色。 最初的Dawn Demo由NVIDIA于2002年发布&#xff0c;…

GPU Gems1 - 5 改良的Perlin噪声的实现

Perlin 噪声 KenPerlin(1985a,2002)KenPerlin(1985a,2002) 定义的噪声函数是最常用的噪声函数&#xff0c;称为 Perlin 噪声。PerlinPerlin 噪声在全部 (x,y,z)(x,y,z) 整形顶点处的参数值都为 00&#xff0c;变化源自各顶点间的梯度向量&#xff0c;然后再进行平滑插值。 计算…

GPU Gems1 - 7 无数波动草叶的渲染

本文部分参照该文章https://zhuanlan.zhihu.com/p/35974789 1.引言 本章介绍了一种灵活的&#xff0c;广泛应用的草模拟。该方案渲染的草不仅生长得自然&#xff0c;也能够逼真地在风中舞动&#xff0c;而且性能很高。 2.概述 首先&#xff0c;需要意识到&#xff0c;对单个…

2003文件服务器迁移2016,服务器2016设置文件共享

服务器2016设置文件共享 内容精选换一换为了保证使用生成的镜像创建的新云服务器可以实现一键式重置密码功能&#xff0c;建议您安装密码重置插件CloudResetPwdAgent&#xff0c;可以应用一键式重置密码功能&#xff0c;给云服务器设置新密码。下载一键式重置密码插件CloudRese…

GPU Gems1 - 8 衍射的模拟

1.什么是衍射 小尺度的表面细节引起反射波彼此干扰&#xff0c;这个现象就是衍射。首先&#xff0c;计算机绘图的大多数表面反射模型都忽略自然光的波动效果。当表面的细节比光的波长&#xff08;约1um&#xff09;大许多时&#xff0c;不存在问题。但对于小尺寸的细节&#x…

GPU Gems1 - 9 有效的阴影体渲染

这章全面讲述了用于实时阴影渲染中常见两种流派之一的阴影体&#xff08;Shadow Volumes&#xff09;技术&#xff0c;又称模板阴影&#xff08;Stencil Shadows&#xff09;技术&#xff0c;重点是得到正确的角度的情形&#xff0c;减少几何图形和填充率的消耗。 简单谈谈阴影…

GPU Gems1 - 10 电影级的光照

本章中介绍了一个的简化的uberlight&#xff08;可理解为“全能光照”&#xff09;实现&#xff0c;此光照shader根据Ronen Barzel(1997,1999)提出的照明模型编写而成。而该模型的超集已由Pixar动画开发&#xff0c;并应用于《玩具总动员》、《怪物公司》、《海底总动员》等一系…