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 }

    效果如下:

  • 相关阅读:
    nginx能访问html静态文件但无法访问php文件
    LeetCode "498. Diagonal Traverse"
    LeetCode "Teemo Attacking"
    LeetCode "501. Find Mode in Binary Search Tree"
    LeetCode "483. Smallest Good Base" !!
    LeetCode "467. Unique Substrings in Wraparound String" !!
    LeetCode "437. Path Sum III"
    LeetCode "454. 4Sum II"
    LeetCode "445. Add Two Numbers II"
    LeetCode "486. Predict the Winner" !!
  • 原文地址:https://www.cnblogs.com/koshio0219/p/11169122.html
Copyright © 2011-2022 走看看