ro-webgl/Assets/Shaders/PostEffect/DepthOfField.shader
2021-12-21 09:40:39 +08:00

142 lines
4.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "PostEffect/DepthOfField" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_BlurTex("Blur", 2D) = "white"{}
}
CGINCLUDE
#include "UnityCG.cginc"
struct v2f_blur
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 uv01 : TEXCOORD1;
float4 uv23 : TEXCOORD2;
float4 uv45 : TEXCOORD3;
};
struct v2f_dof
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uv1 : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_TexelSize;
sampler2D _BlurTex;
sampler2D_float _CameraDepthTexture;
float4 _offsets;
float _focalDistance;
float _nearBlurScale;
float _farBlurScale;
//高斯模糊 vert shader上一篇文章有详细注释
v2f_blur vert_blur(appdata_img v)
{
v2f_blur o;
_offsets *= _MainTex_TexelSize.xyxy;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);
o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;
o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;
return o;
}
//高斯模糊 pixel shader上一篇文章有详细注释
fixed4 frag_blur(v2f_blur i) : SV_Target
{
fixed4 color = fixed4(0,0,0,0);
color += 0.40 * tex2D(_MainTex, i.uv);
color += 0.15 * tex2D(_MainTex, i.uv01.xy);
color += 0.15 * tex2D(_MainTex, i.uv01.zw);
color += 0.10 * tex2D(_MainTex, i.uv23.xy);
color += 0.10 * tex2D(_MainTex, i.uv23.zw);
color += 0.05 * tex2D(_MainTex, i.uv45.xy);
color += 0.05 * tex2D(_MainTex, i.uv45.zw);
return color;
}
//景深效果 vertex shader
v2f_dof vert_dof(appdata_img v)
{
v2f_dof o;
//mvp矩阵变换
o.pos = UnityObjectToClipPos(v.vertex);
//uv坐标传递
o.uv.xy = v.texcoord.xy;
o.uv1.xy = o.uv.xy;
//dx中纹理从左上角为初始坐标需要反向
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv.y = 1 - o.uv.y;
#endif
return o;
}
fixed4 frag_dof(v2f_dof i) : SV_Target
{
//取原始清晰图片进行uv采样
fixed4 ori = tex2D(_MainTex, i.uv1);
//取模糊普片进行uv采样
fixed4 blur = tex2D(_BlurTex, i.uv);
//取当位置对应的深度值
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
//将深度值转化到01线性空间
depth = Linear01Depth(depth);
//如果depth小于焦点的物体那么使用原始清晰图像否则使用模糊的图像与清晰图像的差值通过差值避免模糊和清晰之间明显的边界结果为远景模糊效果
fixed4 final = (depth <= _focalDistance) ? ori : lerp(ori, blur, clamp((depth - _focalDistance) * _farBlurScale, 0, 1));
//上面的结果再进行一次计算如果depth大于焦点的物体使用上面的结果和模糊图像差值得到近景模糊效果
final = (depth > _focalDistance) ? final : lerp(ori, blur, clamp((_focalDistance - depth) * _nearBlurScale, 0, 1));
//焦点位置是清晰的图像,两边分别用当前像素深度距离焦点的距离进行差值,这样就达到原理焦点位置模糊的效果
//上面的在编译时会被编译成if语句GPU并不擅长分支计算而且如果有分支两个分支都要跑。这里给了一个更优化一些的计算方式不过语法比较晦涩
/*float focalTest = clamp(sign(depth - _focalDistance),0,1);
fixed4 final = (1 - focalTest) * ori + focalTest * lerp(ori, blur, clamp((depth - _focalDistance) * _farBlurScale, 0, 1));
final = (focalTest)* final + (1 - focalTest) * lerp(ori, blur, clamp((_focalDistance - depth) * _nearBlurScale, 0, 1)); */
return final;
}
ENDCG
SubShader
{
//pass 0: 高斯模糊
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
CGPROGRAM
#pragma vertex vert_blur
#pragma fragment frag_blur
ENDCG
}
//pass 1: 景深效果
Pass
{
ZTest Off
Cull Off
ZWrite Off
Fog{ Mode Off }
ColorMask RGBA
CGPROGRAM
#pragma vertex vert_dof
#pragma fragment frag_dof
ENDCG
}
}
}