Bloom效果【Unity Shader入門精要12.5】
阿新 • • 發佈:2018-12-17
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' //12.5 Bloom效果 Shader "Unlit/Chapter12-Bloom" { Properties { //宣告屬性 _MainTex ("Base(RGB)", 2D) = "white" {} _Bloom("Bloom(RGB)",2D)="black"{} _LumianceThreshold("Luminace 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; //1.定義提亮區域需要使用的頂點著色器和片元著色器 struct v2f { float4 pos:SV_POSITION; half2 uv:TEXCOORD0; }; //頂點 v2f vertExtractBright(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 fragExtractBright(v2f i):SV_Target { fixed4 c = tex2D(_MainTex, i.uv); //將取樣的到的亮度 - 閥值,並把結果擷取到0到1 fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0); //然後把上面的值和原畫素值相乘,得到提取後的亮度區域 return c * val; } //4.定義混合亮度部分影象和原影象時使用的頂點片元著色器 struct v2fBloom { float4 pos:SV_POSITION; half4 uv:TEXCOORD0; }; v2fBloom vertBloom(appdata_img v) { v2fBloom o; o.pos = UnityObjectToClipPos(v.vertex); //定義了兩個紋理座標並儲存在同一個型別為half4的變數uv中 o.uv.xy = v.texcoord; o.uv.zw = v.texcoord; /*判斷當前平臺是否是DirectX型別的平臺. 當在這樣的平臺下開啟了抗鋸齒後,主紋理的紋素值大小在豎直方向上會變成負值,以便我們對主紋理進行正確的取樣*/ #if UNITY_UV_STARTS_AT_TOP //因此可以通過判斷_MainTex_TexelSize.y 是否小於0來檢測是否開啟了抗鋸齒 if (_MainTex_TexelSize.y < 0.0) //如果是,就需要對除主紋理外的其他紋理的取樣座標進行豎直方向上的翻轉 /*由於要同時處理多張紋理,因此在DirectX這樣的平臺下如果開啟了抗鋸齒, 主紋理和亮度在豎直方向上的朝向就是不同的了,就需要對亮度紋理的取樣座標進行翻轉*/ o.uv.w = 1.0 - o.uv.w; #endif return o; } fixed4 fragBloom(v2fBloom i) :SV_Target{ //uv的xy對應了_MainTex.即原影象的紋理座標,zw對應_Bloom,即模糊後的較亮區域的紋理座標 return tex2D(_MainTex,i.uv.xy) + tex2D(_Bloom,i.uv.zw); } ENDCG //定義Bloom效果的4個Pass ZTest Always Cull Off ZWrite Off //1.提取亮度 Pass { CGPROGRAM #pragma vertex vertExtractBright #pragma fragment fragExtractBright ENDCG } //2.使用12.4的高斯模糊 UsePass "Unlit/Chapter12-GaussianBlur/GAUSSIAN_BLUR_VERTICAL" //3.使用12.4的高斯模糊 UsePass "Unlit/Chapter12-GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL" //4.混合 Pass{ CGPROGRAM #pragma vertex vertBloom #pragma fragment fragBloom ENDCG } } Fallback off }
using System.Collections; using System.Collections.Generic; using UnityEngine; //12.5 Bloom 效果 public class Bloom : PostEffectsBase { //宣告效果使用的shader,並據此建立材質 public Shader bloomShader; private Material bloomMaterial = null; public Material material { get { bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial); return bloomMaterial; } } //迭代次數 [Range(0, 4)] public int iterations = 3; //模糊程度 [Range(0.2f, 3.0f)] public float blurSpread = 0.6f; //取樣次數 [Range(1, 8)] public int downSample = 2; //亮度閾值 [Range(0.0f, 4.0f)] public float luminanceThreshold = 0.6f; /*絕大多數情況下,影象的亮度值不會超過一。 但如果開啟了HDR,硬體會允許我們把顏色值儲存在一個更高精度範圍的緩衝中,此時畫素的亮度值可能會超過1*/ /*bloom需要三個步驟 1:提取影象中最亮的區域, 2:高斯模糊迭代處理 3:混合*/ private void OnRenderImage(RenderTexture src, RenderTexture dest) { if (material !=null ) {//1: material.SetFloat("_LuminanceThreshold", luminanceThreshold); int rtW = src.width / downSample; int rtH = src.height / downSample; RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0); buffer0.filterMode = FilterMode.Bilinear; //使用Shader中的第一個Pass提取影象中較亮的區域,將提取到的儲存在buffer中 Graphics.Blit(src, buffer0, material, 0); for (int i = 0; i < iterations; i++) { //2: material.SetFloat("_BlurSize", 1.0f + i * blurSpread); RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0); //shader的第二個pass Graphics.Blit(buffer0, buffer1, material, 1); RenderTexture.ReleaseTemporary(buffer0); buffer0 = buffer1; buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0); //shader的第三個pass Graphics.Blit(buffer0, buffer1, material, 2); RenderTexture.ReleaseTemporary(buffer0); //將模糊後的區域儲存在buffer0 中 buffer0 = buffer1; } //3: //將buffer0傳遞給材質中的_Bloom紋理屬性 material.SetTexture("_Bloom", buffer0); //使用第四個pass進行混合,儲存在目標渲染紋理dest中 Graphics.Blit(src, dest, material, 3); //釋放臨時快取 RenderTexture.ReleaseTemporary(buffer0); }else { Graphics.Blit(src, dest); } } }