效果
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] [ImageEffectAllowedInSceneView] public class Bloom : MonoBehaviour { #region constData const int firstPass = 0; const int downPass = 1; const int upPass = 2; const int mixPass = 3; #endregion public Shader bloom; private Material material; [Range(0,8)] public int Interations; [Range(1,10)]// 已经限定从1开始, 只有开启HDR的才会开启bloom public float Threshold =1; [Range(0,1)] public float SoftThreshold = 0.5f; [Range(0,10)] public float Intensity = 1; RenderTexture[] textures = new RenderTexture[8]; private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (!material) { material = new Material(bloom); material.hideFlags = HideFlags.HideAndDontSave; } material.SetFloat("_Threshold", Threshold); material.SetFloat("_Intensity", Intensity); float knee = Threshold - SoftThreshold; Vector4 filter; filter.x = Threshold; filter.y = Threshold - knee; filter.z = 2 * knee; filter.w = 4 * knee + 0.00001f; // 将参数,以V4的形式传递进shader,将计算量留在CPU,减少GPU的计算 material.SetVector("_Filter", filter); int width = source.width; int height = source.height; width /= 2; height /= 2; RenderTextureFormat format = source.format; RenderTexture currentDestination = textures[0] = RenderTexture.GetTemporary(width, height, 0, format); Graphics.Blit(source, currentDestination,material,firstPass); RenderTexture currentSource = currentDestination; int i = 1; // 向下采样 for (; i < Interations; i++) { width /= 2; height /= 2; if (height<2) { break; } currentDestination = textures[i] = RenderTexture.GetTemporary(width, height, 0, format); Graphics.Blit(currentSource, currentDestination,material,downPass); currentSource = currentDestination; } //向上采样 for (i-=2; i>=0; i--) { currentDestination = textures[i]; textures[i] = null; Graphics.Blit(currentSource, currentDestination,material,upPass); RenderTexture.ReleaseTemporary(currentSource); currentSource = currentDestination; } material.SetTexture("_SourceTex", source); //混合 Graphics.Blit(currentDestination, destination,material,mixPass); RenderTexture.ReleaseTemporary(currentDestination); } } |
Shader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
Shader "custom/Bloom" { Properties { _MainTex ("Texture", 2D) = "white" {} //_SourceTex("SourceTex",2D) = "white"{} //_Threshold("_Threshold",float) = 1 //_Filter("_Filter",Vector) = (0,0,0,0) } CGINCLUDE #include "UnityCG.cginc" float _Threshold; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float4 _MainTex_TexelSize; sampler2D _SourceTex; float4 _SourceTex_ST; vector _Filter; float _Intensity; half3 Sample(float2 uv) { return tex2D(_MainTex,uv).rgb; } // half3 SampleBox(float2 uv,float detail) { float4 o = _MainTex_TexelSize.xyxy * float4(-detail,-detail,detail,detail); half3 c = Sample(uv+ o.xy) + Sample(uv + o.xz) + Sample(uv+o.zw) +Sample(uv+o.zx); return c*0.25; } // half3 Prefilter(half3 c) // { // half brightness = max(c.r,max(c.g,c.b)); // half contribution = max(0,brightness - _Threshold); // contribution /= max(brightness,0.00001); // return contribution; // } half3 Prefilter(half3 c) { half brightness = max(c.r,max(c.g,c.b)); half soft = brightness - _Filter.y; soft = clamp(soft,0,_Filter.z); soft = soft * soft/_Filter.w; half contribution = max(soft,brightness- _Filter.x); contribution /= max(brightness,0.00001); return contribution*c; } ENDCG SubShader { // No culling or depth Cull Off ZWrite Off ZTest Always Pass { //像素的预筛选 CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag (v2f i) : SV_Target { half3 col = Prefilter(SampleBox(i.uv,1)); return fixed4(col,1); } ENDCG } Pass { //下采样 CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag (v2f i) : SV_Target { half3 col = SampleBox(i.uv,1); return fixed4(col,1); } ENDCG } Pass { Blend One One // 上采样 CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag (v2f i) : SV_Target { half3 col = SampleBox(i.uv,0.5); return fixed4(col,1); } ENDCG } Pass { //混合 CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag (v2f i) : SV_Target { half3 col = SampleBox(i.uv,0.5) + tex2D(_SourceTex,i.uv).rgb * _Intensity; //half3 col = SampleBox(i.uv,1); return fixed4(col,1); } ENDCG } } } |
使用方法
将脚本挂载到相机上,然后将拖入shader
- 本文固定链接: http://www.u3d8.com/?p=2528
- 转载请注明: 网虫虫 在 u3d8.com 发表过