![cd2200f8a30f4c5c452eeddf5c5db14b.png](https://i-blog.csdnimg.cn/blog_migrate/238131b0141d9ceed72f59f1ab005bd2.jpeg)
刚才看了个关于渲染的问题,跟答主吹逼说会写bloom效果。
口说无凭,现在就来写。本文为学习交流目的,请各路大佬批判。
所谓bloom效果,也叫泛光效果,指发光或反光物体周围带光晕的效果。此类效果的实现思路是,在已经渲染好的一帧画面上,把需要泛光效果的区域提取出来,进行一次模糊,再叠加到原图上去。
所以,这个效果分三步,提取区域,模糊,叠加。Shader就按照这样的步骤写,一个步骤一个pass。
一、shader。
1.提取区域。
按亮度提取区域的效果不是很好,会提取我们不需要的区域。我们把需要提取的颜色用透明度通道标记一下,只要不用blend命令,这个透明度也会储存在屏幕图片的像素上,但完全不影响显示效果。在这个场景中,我写了个溶解的shader,溶解边缘的颜色为
![0e051f97c196dec2a2d39aabfc54c713.png](https://i-blog.csdnimg.cn/blog_migrate/9aab4f36248fe474426e525adceb11fa.png)
可以看到不完全透明。
我们拿到当前屏幕图片,在片元着色器中判断每个像素的透明度值,如果小于1则返回本颜色,等于1则返回黑色。
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag_Alpha
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 frag_Alpha(v2f_img i):SV_Target
{
fixed4 result = tex2D(_MainTex,i.uv);
return result.a<1 ? fixed4(result.rgb,1):fixed4(0,0,0,0);
}
ENDCG
}
2.模糊。
模糊的算法有很多,我们用高斯模糊算法。所有的模糊算法都是利用周遭像素值加权叠加计算得到结果的,权重取决于距离。我们在此不用烂大街的横竖七位十字架,实打实计算像素和周围一圈,共9个像素。根据枯燥的计算,中心像素权重0.1478,四个相邻像素权重0.1183,四个对角像素权重0.0947。在图片上采样到各个像素颜色值,和对应权重相乘,加到一起即得结果。
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _AlphaTex;
fixed4 _AlphaTex_TexelSize;
struct v2f
{
fixed4 pos:SV_POSITION;
fixed2 uv:TEXCOORD0;
fixed4 uv1:TEXCOORD1;
fixed4 uv2:TEXCOORD2;
fixed4 uv3:TEXCOORD3;
fixed4 uv4:TEXCOORD4;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.uv1.xy = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(-1,-1);
o.uv1.zw = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(-1,0);
o.uv2.xy = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(-1,1);
o.uv2.zw = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(0,-1);
o.uv3.xy = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(0,1);
o.uv3.zw = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(1,-1);
o.uv4.xy = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(1,0);
o.uv4.zw = v.texcoord.xy + _AlphaTex_TexelSize.xy*fixed2(1,1);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 color = fixed3(0,0,0);
color += tex2D(_AlphaTex, i.uv)*0.1478;
color += tex2D(_AlphaTex, i.uv1.xy)*0.0947;
color += tex2D(_AlphaTex, i.uv2.xy)*0.0947;
color += tex2D(_AlphaTex, i.uv3.xy)*0.1183;
color += tex2D(_AlphaTex, i.uv4.xy)*0.1183;
color += tex2D(_AlphaTex, i.uv1.zw)*0.1183;
color += tex2D(_AlphaTex, i.uv2.zw)*0.1183;
color += tex2D(_AlphaTex, i.uv3.zw)*0.0947;
color += tex2D(_AlphaTex, i.uv4.zw)*0.0947;
return fixed4(color,1);
}
3.叠加。
这个没啥技术含量,就是模糊过的图片和原屏幕图片颜色值相加。因为不需要bloom的区域是黑色也就是(0,0,0),所以除了bloom效果的泛光区,叠加是不影响原颜色值的。
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag_add
sampler2D _BloomTex;
sampler2D _MainTex;
fixed4 frag_add(v2f_img i):SV_Target
{
fixed3 color1 = tex2D(_MainTex, i.uv).rgb;
fixed3 color2 = tex2D(_BloomTex, i.uv).rgb;
return fixed4(color1+color2, 1);
}
ENDCG
}
二、C#。
后处理脚本更简单,getTemporary两个RenderTexture,将原屏幕图提取颜色后的区域储存到第一个RenderTexture,将第一个RenderTexture模糊后存储到第二个RenderTexture,然后把第二个RenderTexture和原屏幕图相加,输出到指定的输出纹理上即可。别忘了释放RenderTexture。
using
泛光程度intensity就是降采样的分母,越大泛光越严重,但是过大的话效果就不堪入目了。
//我再把溶解的shader放上来吧,虽然不难,但如果能帮到新手也是极好的。
Shader "Custom/Dissolved"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Noise ("噪音图", 2D) = "white" {}
_EdgeColor("边缘颜色",Color)=(1,1,1,1)
_EdgeWidth("边缘宽度",Range(0,1))=0.2
_Cut("溶解程度", Range(0,1))=0.5
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
sampler2D _Noise;
fixed4 _EdgeColor;
float _EdgeWidth;
float _Cut;
struct a2v
{
fixed4 vertex:POSITION;
fixed3 normal:NORMAL;
fixed4 texcoord:TEXCOORD0;
};
struct v2f
{
fixed4 pos:SV_POSITION;
fixed2 uv:TEXCOORD0;
fixed3 worldNormal:TEXCOORD1;
fixed3 worldPos:TEXCOORD2;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.uv = v.texcoord.xy;
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i):SV_Target
{
float r = tex2D(_Noise, i.uv).r;
clip(r-_Cut);
if(r-_Cut<_EdgeWidth)
{
return _EdgeColor;
}
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = albedo*UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 l = normalize(_WorldSpaceLightPos0.xyz - _WorldSpaceLightPos0.w*i.worldPos);
float NdotL = max(0,dot(l, i.worldNormal));
fixed3 diffuse = albedo*NdotL;
return fixed4(ambient + diffuse, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}