shader特效
Bloom后处理效果
Bloom的cs代码
using System.Collections.Generic;
using UnityEngine;
public class bloom : PostEffectsBase
{
public Shader bloomShader;
private Material bloomMaterial;
public Material material
{
get
{
//根据PostEffectsBase中的方法检测,第一个参数指定了该特效需要使用的Shader,第二个参数则是用于后期处理的材质;
//该函数首先检查Shader的可用性,检查通过后返回一个使用了该shader的材质,否则返回Null.
bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);
return bloomMaterial;
}
}
//高斯模糊的叠带次数
[Range(0, 4)]
public int iterations = 3;
//高斯模糊的叠带范围
[Range(0.2f, 4.0f)]
public float blurSpread = 0.6f;
//降采样的数值
[Range(1, 8)]
public int downSample = 2;
//luminanceThreshold,大多数情况下图像亮度不会超过1.但如果我们开启了HDR,硬件会允许我们把颜色值储存在一个更高精度范围的缓冲中,
//此时像素的亮度就会超过1.
[Range(0.0f, 4.0f)]
public float luminanceThreshold = 0.6f;
//OnRenderImage函数
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (material != null)
{
material.SetFloat("_luminanceThreshold", luminanceThreshold);
//将图像进行降采样不仅可以减少需要处理的像素,提高性能,而且适当的降采样旺旺还可以得到更好的模糊效果
int rtW = src.width / downSample;
int rtH = src.height / downSample;
//定义第一个缓存buffer0,并吧src中的图像缩放后储存到buffer0中。
RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
buffer0.filterMode = FilterMode.Bilinear;
//调用shader中的第一个Pass提取图像中较亮的区域,提到的较亮区域将储存在buffer0 中。
Graphics.Blit(src, buffer0, material, 0);
for (int i = 0; i < iterations; i++)
{
material.SetFloat("_BlurSize", 1.0f + i * blurSpread);
//定义buffer1
RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
//调用第二个pass,输入buffer0,输出buffer1.
Graphics.Blit(buffer0, buffer1, material, 1);
RenderTexture.ReleaseTemporary(buffer0);
//将输出的buffer1重新赋值给buffer0
buffer0 = buffer1;
buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
//调用第三个pass,输入buffer0(上面输出的buffer1),输出buffer1(新的buffer1)
Graphics.Blit(buffer0, buffer1, material, 2);
//将新的buffer1再次给buffer0赋值
buffer0 = buffer1;
}
//第四个Pass,将buffer0赋值给贴图_Bloom
material.SetTexture("_Bloom", buffer0);
Graphics.Blit(src, dest, material, 3);
RenderTexture.ReleaseTemporary(buffer0);
}
else
{
Graphics.Blit(src, dest);
}
}
}
PostEffectsBase的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//在编辑器状态下可执行该脚本来查看效果
[ExecuteInEditMode]
//屏幕后处理特效一般需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
public class PostEffectsBase : MonoBehaviour
{
void Start()
{
CheckResources();
}
protected void CheckResources()
{
bool isSupported = CheckSupport();
//如果显卡检测 返回false
if (isSupported == false)
{
//NotSupported()方法,即不显示
NotSupported();
}
}
//检查显卡是否支持
protected bool CheckSupport()
{
//如果显卡不支持图像后期处理
if (SystemInfo.supportsImageEffects == false)
{
//返回false
return false;
}
//如果支持图像后处理,返回true
return true;
}
//图像不显示
protected void NotSupported()
{
enabled = false;
}
//CheckShaderAndCreateMaterial函数接受两个参数,第一个参数指定了改特效需要使用的Shader
//第二个参数则是用于后期处理的材质。该函数首先检查Shader的可用性,检查通过后就返回一个使
//用了该shader的材质,否则返回null.
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
{ //如果shader为空
if (shader == null)
{
return null;
}
//shader.isSupported:能在终端用户的图形卡上运行这个着色器&& 并且存在material 他的shader是我们输入的shader
if (shader.isSupported && material && material.shader == shader)
{
return material;
}
if (!shader.isSupported)
{
return null;
}
//上面都不满足的话,重新创建新的材质球
else
{
material = new Material(shader);
//hideFlags:控制对象销毁的位掩码
//HideFlags.DontSave对象不会保存到场景中。加载新场景时不会被破坏。
material.hideFlags = HideFlags.DontSave;
return material;
}
}
}
shader代码:
Shader "Unlit/Bloom"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
//高斯模糊较亮的区域
_Bloom("Bloom(RGB)",2D) = "Black"{}
//阔值,提取大于这个亮度的区域 后面将在 大于这个值 的区域里进行高斯模糊
_luminanceThreshold("luminanceThreshold",Float) = 0.5
//控制不同迭代之间高斯模糊的模糊区域范围 也就是uv偏移的范围
_BlurSize("Blur Size",Float) = 1.0
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_TexelSize;
sampler2D _Bloom;
Float _luminanceThreshold;
float _BlurSize;
///提取交亮区域的 顶点.片元 着色器
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;
}
//通过主贴图得到一个灰度值
fixed4 luminance(fixed4 color) {
return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
fixed4 fragExtractBright(v2f i) :SV_Target {
///我们降采样得到的亮度值减去阔值_luminanceThreshold,并把结果截取到0到1的范围内,然后
///我们把该值和原像素相乘,得到提取后的两部区域
///这样就是低于_luminanceThreshold显示为黑色
fixed c = tex2D(_MainTex , i.uv);
//clamp(x,a,b),如果x<a,返回a,x>b,返回b,否则返回为x;
fixed val = clamp(luminance(c) - _luminanceThreshold, 0.0, 1.0);
return c * val;
}
///使用Unity提供的_MainTex_Texel_TexelSize变量,计算相邻文理坐标的的偏移(也是高斯模糊的写法)
//竖方向跟横方向的两个顶点着色器公用的v2f输出定义
struct v2fBlur {
float4 pos : SV_POSITION;
half2 uv[5]:TEXCOORD0;
};
//竖直方向的
v2fBlur vertBlurV(appdata_img v) {
v2fBlur o;
o.pos = UnityObjectToClipPos(v.vertex);
half2 uv = v.texcoord;
o.uv[0] = uv;
o.uv[1] = uv + float2 (0.0,_MainTex_TexelSize.y * 1.0) * _BlurSize;
o.uv[2] = uv - float2 (0.0,_MainTex_TexelSize.y * 1.0) * _BlurSize;
o.uv[3] = uv + float2 (0.0,_MainTex_TexelSize.y * 2.0) * _BlurSize;
o.uv[4] = uv - float2 (0.0,_MainTex_TexelSize.y * 2.0) * _BlurSize;
return o;
}
//水平方向的
v2fBlur vertBlurH(appdata_img v) {
v2fBlur o;
o.pos = UnityObjectToClipPos(v.vertex);
half2 uv = v.texcoord;
o.uv[0] = uv;
o.uv[1] = uv + float2 (_MainTex_TexelSize.x * 1.0 , 0.0) * _BlurSize;
o.uv[2] = uv - float2 (_MainTex_TexelSize.x * 1.0 , 0.0) * _BlurSize;
o.uv[3] = uv + float2 (_MainTex_TexelSize.x * 2.0 , 0.0) * _BlurSize;
o.uv[4] = uv - float2 (_MainTex_TexelSize.x * 2.0 , 0.0) * _BlurSize;
return o;
}
//定义两个pass公用的片元着色器
fixed4 fragBlur(v2fBlur i) : SV_Target{
float weight[3] = {0.4026, 0.2442, 0.0545};
fixed3 sum = tex2D(_MainTex,i.uv[0]).rgb * weight[0];
for (int j = 1; j < 3; j++) {
sum += tex2D(_MainTex,i.uv[j * 2 - 1]).rgb * weight[j];
sum += tex2D(_MainTex,i.uv[j * 2]).rgb * weight[j];
}
return fixed4(sum,1.0);
}
///混合亮部图像和原图像时使用的 顶点.片元 着色器
struct v2fBloom {
float4 pos :SV_POSITION;
half4 uv :TEXCOORD0;
};
v2fBloom vertBloom(appdata_img v) {
v2fBloom o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.texcoord;
o.uv.zw = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0)
o.uv.w = 1.0 - o.uv.w;
#endif
return o;
}
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 {
CGPROGRAM
#pragma vertex vertExtractBright
#pragma fragment fragExtractBright
ENDCG
}
pass {
CGPROGRAM
#pragma vertex vertBlurV
#pragma fragment fragBlur
ENDCG
}
pass {
CGPROGRAM
#pragma vertex vertBlurH
#pragma fragment fragBlur
ENDCG
}
pass {
CGPROGRAM
#pragma vertex vertBloom
#pragma fragment fragBloom
ENDCG
}
}
FallBack Off
}
毛发效果
cginc的代码:
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uv1 : TEXCOORD1;
fixed4 diff : COLOR;
};
float _FurLength;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _FurTex;
float4 _FurTex_ST;
float _Blur;
v2f vert(appdata_base v)
{
v2f o;
v.vertex.xyz += v.normal * _FurLength * FURSTEP;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv1 = TRANSFORM_TEX(v.texcoord, _FurTex);
float3 worldNormal = normalize(mul(v.normal, (float3x3) unity_WorldToObject));
o.diff = LambertDiffuse(worldNormal);
o.diff.a = 1 - (FURSTEP * FURSTEP);
float4 worldPos = mul(unity_ObjectToWorld ,v.vertex);
o.diff.a += dot(normalize(_WorldSpaceCameraPos.xyz- v.vertex), worldNormal) - _Blur;
return o;
}
float _CutOff;
float _Thickness;
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed alpha = tex2D(_FurTex, i.uv1).r;
col *= i.diff;
col.a *= step(lerp(_CutOff, _CutOff + _Thickness, FURSTEP), alpha);
return col;
}
shader代码:
Shader "Custom/FurShader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_FurTex("Fur pattern", 2D) = "white" {}
_Diffuse("Diffuse value", Range(0, 3)) = 1
_FurLength("Fur length", Range(0.0, 1)) = 0.5
_CutOff("Alpha cutoff", Range(0, 1)) = 0.5
_Blur("Blur", Range(0, 1)) = 0.5
_Thickness("Thickness", Range(0, 0.5)) = 0
}
CGINCLUDE
fixed _Diffuse;
inline fixed4 LambertDiffuse(float3 worldNormal)
{
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float NdotL = max(0.2, dot(worldNormal, lightDir));
return NdotL * _Diffuse;
}
ENDCG
SubShader
{
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" "LightMode" = "ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.05
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.10
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.15
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.20
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.25
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.30
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.35
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.40
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.45
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.50
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.55
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.60
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.65
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.70
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.75
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.80
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.85
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.90
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FURSTEP 0.95
#include "UnityCG.cginc"
#include "FurHelper.cginc"
ENDCG
}
}
}