Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

Unity Shader 屏幕后效果——Bloom外发光

汐夜 2019-07-11 11:55:00 阅读数:351 评论数:0 点赞数:0 收藏数:0

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

 

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

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

 

计算方法:

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

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

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

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

 

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

 

控制脚本:

 using UnityEngine;

public class BloomCtrl : ScreenEffectBase
 {
 private const string _LuminanceThreshold = "_LuminanceThreshold";
 private const string _BlurSize = "_BlurSize";
 private const string _Bloom = "_Bloom";

[Range(, )]
 public int iterations = ;
 [Range(0.2f, 3.0f)]
 public float blurSize = 0.6f;
 [Range(, )]
 public int dowmSample = ;
 [Range(0.0f, 4.0f)]
 public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大
private void OnRenderImage(RenderTexture source, RenderTexture destination)
  {
 if (Material != null)
  {
  Material.SetFloat(_LuminanceThreshold, luminanceThreshold);

int rth = source.height / dowmSample;
 int rtw = source.width / dowmSample;

RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, );
 buffer0.filterMode = FilterMode.Bilinear;

//第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
Graphics.Blit(source, buffer0,Material,);

for(int i = ; i < iterations; i++)
  {
 Material.SetFloat(_BlurSize, blurSize*i+1.0f);

//第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, );
 Graphics.Blit(buffer0, buffer1, Material,);
 RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release();
buffer0 = RenderTexture.GetTemporary(rtw, rth, );
 Graphics.Blit(buffer1, buffer0, Material, );
  RenderTexture.ReleaseTemporary(buffer1);
  }

//第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
 Material.SetTexture(_Bloom, buffer0);
 Graphics.Blit(source,destination,Material,);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
 RenderTexture.ReleaseTemporary(buffer0);
  }
 else
 Graphics.Blit(source, destination);
  }
 }

 

Shader脚本:

 Shader "MyUnlit/Bloom"
{
  Properties
  {
 _MainTex ("Texture", 2D) = "white" {}
 _Bloom("Bloom",2D)="black"{}
 _LuminanceThreshold("Luminance Threshold",Float)=0.5
_BlurSize("Blur Size",Float)=1.0
 }
  SubShader
  {
  CGINCLUDE

#include "UnityCG.cginc"
 sampler2D _MainTex;
  half4 _MainTex_TexelSize;
  sampler2D _Bloom;
 float _LuminanceThreshold;
 float _BlurSize;

struct v2f
  {
  half2 uv : TEXCOORD0;
  float4 pos : SV_POSITION;
  };

struct v2fBloom
  {
 //half4是因为这里还要存储_Bloom纹理
 half4 uv:TEXCOORD0;
  float4 pos:SV_POSITION;
  };

 v2f vert(appdata_img v)
  {
  v2f o;
 o.pos=UnityObjectToClipPos(v.vertex);
 o.uv=v.texcoord;
 return o;
  }

 v2fBloom vertBloom(appdata_img v)
  {
  v2fBloom o;
 o.pos=UnityObjectToClipPos(v.vertex);

//xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
o.uv.xy=v.texcoord;
 o.uv.zw=v.texcoord;

//纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
 //同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
 //主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
#if UNITY_UV_STARTS_AT_TOP
if(_MainTex_TexelSize.y<){
 o.uv.w=1.0-o.uv.w;
  }
 #endif
return o;
  }

//提取超过亮度阈值的图像
 fixed4 fragExtractBright(v2f i):SV_Target
  {
 fixed4 col=tex2D(_MainTex,i.uv);
 fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
 return col*val;
  }

//对xy和zw对应的纹理采样进行混合
 fixed4 fragBloom(v2fBloom i):SV_Target
  {
 return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
  }

 ENDCG

 ZTest Always
  Cull Off
  ZWrite Off

//Pass 1:提亮部
 Pass
  {
  CGPROGRAM
 #pragma vertex vert
#pragma fragment fragExtractBright
 ENDCG
  }

//Pass 2,3:高斯模糊,这里直接调用以前写的Pass
UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V"
UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H"
//Pass 4:混合原图和模糊后亮部
 Pass
  {
  CGPROGRAM
 #pragma vertex vertBloom
#pragma fragment fragBloom
 ENDCG
  }
  }
  Fallback Off
 }

 

效果如下:

 

版权声明
本文为[汐夜]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/koshio0219/p/11169122.html