zoukankan      html  css  js  c++  java
  • Unity Shader 屏幕后效果——Bloom外发光

    Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成。

    一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客:

    https://www.cnblogs.com/koshio0219/p/11152534.html

    计算方法:

    总共需要用到4个Pass,它们的顺序如下:

    Pass 1:得到纹理的亮度值(灰度值),由此计算出亮部区域,传递给一个临时的新纹理,这里叫_Bloom

    Pass 2,3:单独对_Bloom进行高斯模糊(纵横),_Bloom纹理更新

    Pass 4:混合原始纹理和_Bloom纹理,得到最终效果

    为了得到更为细致的Bloom效果,建议将游戏的颜色空间由默认的伽马空间转为线性空间,必要时还可开启HDR

    控制脚本:

     1 using UnityEngine;
     2 
     3 public class BloomCtrl : ScreenEffectBase
     4 {
     5     private const string _LuminanceThreshold = "_LuminanceThreshold";
     6     private const string _BlurSize = "_BlurSize";
     7     private const string _Bloom = "_Bloom";
     8 
     9     [Range(0, 4)]
    10     public int iterations = 3;
    11     [Range(0.2f, 3.0f)]
    12     public float blurSize = 0.6f;
    13     [Range(1, 8)]
    14     public int dowmSample = 2;
    15     [Range(0.0f, 4.0f)]
    16     public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大
    17 
    18     private void OnRenderImage(RenderTexture source, RenderTexture destination)
    19     {
    20         if (Material != null)
    21         {
    22             Material.SetFloat(_LuminanceThreshold, luminanceThreshold);
    23 
    24             int rth = source.height / dowmSample;
    25             int rtw = source.width / dowmSample;
    26 
    27             RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
    28             buffer0.filterMode = FilterMode.Bilinear;
    29 
    30             //第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
    31             Graphics.Blit(source, buffer0,Material,0);
    32 
    33             for(int i = 0; i < iterations; i++)
    34             {
    35                 Material.SetFloat(_BlurSize, blurSize*i+1.0f);
    36 
    37                 //第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
    38                 RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0);
    39                 Graphics.Blit(buffer0, buffer1, Material,1);
    40                 RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release();
    41 
    42                 buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
    43                 Graphics.Blit(buffer1, buffer0, Material, 2);
    44                 RenderTexture.ReleaseTemporary(buffer1);
    45             }
    46 
    47             //第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
    48             Material.SetTexture(_Bloom, buffer0);
    49             Graphics.Blit(source,destination,Material,3);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
    50             RenderTexture.ReleaseTemporary(buffer0);
    51         }
    52         else
    53             Graphics.Blit(source, destination);
    54     }
    55 }

    基类脚本见:

    https://www.cnblogs.com/koshio0219/p/11131619.html

    Shader脚本:

      1 Shader "MyUnlit/Bloom"
      2 {
      3     Properties
      4     {
      5         _MainTex ("Texture", 2D) = "white" {}
      6         _Bloom("Bloom",2D)="black"{}
      7         _LuminanceThreshold("Luminance Threshold",Float)=0.5
      8         _BlurSize("Blur Size",Float)=1.0
      9     }
     10     SubShader
     11     {
     12         CGINCLUDE
     13 
     14         #include "UnityCG.cginc"
     15 
     16         sampler2D _MainTex;
     17         half4 _MainTex_TexelSize;
     18         sampler2D _Bloom;
     19         float _LuminanceThreshold;
     20         float _BlurSize;
     21 
     22         struct v2f
     23         {
     24            half2 uv : TEXCOORD0;
     25            float4 pos : SV_POSITION;
     26         };
     27 
     28         struct v2fBloom
     29         {
     30            //half4是因为这里还要存储_Bloom纹理
     31            half4 uv:TEXCOORD0;
     32            float4 pos:SV_POSITION;
     33         };
     34 
     35         v2f vert(appdata_img v)
     36         {
     37            v2f o;
     38            o.pos=UnityObjectToClipPos(v.vertex);
     39            o.uv=v.texcoord;    
     40            return o;
     41         }
     42 
     43         v2fBloom vertBloom(appdata_img v)
     44         {
     45            v2fBloom o;
     46            o.pos=UnityObjectToClipPos(v.vertex);
     47 
     48            //xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
     49            o.uv.xy=v.texcoord;
     50            o.uv.zw=v.texcoord;
     51 
     52            //纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
     53            //同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
     54            //主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
     55            #if UNITY_UV_STARTS_AT_TOP
     56            if(_MainTex_TexelSize.y<0){
     57                   o.uv.w=1.0-o.uv.w;
     58            }
     59            #endif
     60 
     61            return o;
     62         }
     63 
     64         //提取超过亮度阈值的图像
     65         fixed4 fragExtractBright(v2f i):SV_Target
     66         {
     67             fixed4 col=tex2D(_MainTex,i.uv);
     68             fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
     69             return col*val;
     70         }
     71 
     72         //对xy和zw对应的纹理采样进行混合
     73         fixed4 fragBloom(v2fBloom i):SV_Target
     74         {
     75             return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
     76         }
     77 
     78         ENDCG
     79 
     80         ZTest Always
     81         Cull Off
     82         ZWrite Off
     83 
     84         //Pass 1:提亮部
     85         Pass
     86         {
     87             CGPROGRAM
     88             #pragma vertex vert
     89             #pragma fragment fragExtractBright     
     90             ENDCG
     91         }
     92 
     93         //Pass 2,3:高斯模糊,这里直接调用以前写的Pass
     94         UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V"
     95 
     96         UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H"
     97 
     98         //Pass 4:混合原图和模糊后亮部
     99         Pass
    100         {
    101             CGPROGRAM
    102             #pragma vertex vertBloom
    103             #pragma fragment fragBloom
    104             ENDCG
    105         }
    106     }
    107     Fallback Off
    108 }

    效果如下:

  • 相关阅读:
    移动端滑动效果
    使用Bash时的几点总结
    docker-It's possible that too few managers are online. Make sure more than half of the managers are online.
    基于elk 实现nginx日志收集与数据分析。
    python-num18 - django进阶一
    文成小盆友python-num17 - django基础
    文成小盆友python-num15 - JavaScript基础
    文成小盆友python-num14 - web 前端基础 html ,css, JavaScript
    文成小盆友python-num13 整个堡垒机
    install pip3 for python 3.x
  • 原文地址:https://www.cnblogs.com/koshio0219/p/11169122.html
Copyright © 2011-2022 走看看