unity实现镜头景深效果
在Unity中,如何实现镜头景深效果呢?今天我们就来详细探讨这个问题。废话不多说,直接上代码。
Shader "Hidden/Render DOF Factor" {
Properties {
_MainTex ("Base", 2D) = "white" {}
_Cutoff ("Cutoff", float) = 0.5
}
// Helper code used in all of the below subshaders
CGINCLUDE
struct v2f {
float4 pos : POSITION;
float depth : TEXCOORD0;
};
struct v2f_uv {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float depth : TEXCOORD1;
};
uniform float4 _FocalParams;
half DOFFactor( float z ) {
float focalDist = _FocalParams.x;
float invRange = _FocalParams.w;
float fromFocal = z - focalDist;
if( fromFocal < 0.0 )
fromFocal *= 4.0;
return saturate( abs( fromFocal ) * invRange );
}
uniform sampler2D _MainTex;
uniform float _Cutoff;
half4 frag(v2f i) : COLOR {
return DOFFactor(i.depth);
}
half4 frag_uv(v2f_uv i) : COLOR {
half4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a - _Cutoff );
return DOFFactor(i.depth);
}
ENDCG
Category {
Fog { Mode Off }
// regular opaque objects
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
v2f vert( appdata_base v ) {
v2f o;
o.pos = mul(glstate.matrix.mvp, v.vertex);
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
// transparent cutout objects
SubShader {
Tags { "RenderType"="TransparentCutout" }
Pass {
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_uv
#include "UnityCG.cginc"
v2f_uv vert( appdata_base v ) {
v2f_uv o;
o.pos = mul(glstate.matrix.mvp, v.vertex);
o.uv = v.texcoord;
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
// terrain tree bark
SubShader {
Tags { "RenderType"="TreeOpaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "TerrainEngine.cginc"
struct appdata {
float4 vertex : POSITION;
float4 color : COLOR;
};
v2f vert( appdata v ) {
v2f o;
TerrainAnimateTree(v.vertex, v.color.w);
o.pos = mul( glstate.matrix.mvp, v.vertex );
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
// terrain tree leaves
SubShader {
Tags { "RenderType"="TreeTransparentCutout" }
Pass {
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_uv
#include "UnityCG.cginc"
#include "TerrainEngine.cginc"
struct appdata {
float4 vertex : POSITION;
float4 color : COLOR;
float4 texcoord : TEXCOORD0;
};
v2f_uv vert( appdata v ) {
v2f_uv o;
TerrainAnimateTree(v.vertex, v.color.w);
o.pos = mul( glstate.matrix.mvp, v.vertex );
o.uv = v.texcoord;
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
// terrain tree billboards
SubShader {
Tags { "RenderType"="TreeBillboard" }
Pass {
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_tree
#include "UnityCG.cginc"
#include "TerrainEngine.cginc"
struct appdata {
float4 vertex : POSITION;
float4 color : COLOR;
float4 texcoord : TEXCOORD0;
};
v2f_uv vert( appdata_tree_billboard v ) {
v2f_uv o;
TerrainBillboardTree(v.vertex, v.texcoord1.xy);
o.pos = mul( glstate.matrix.mvp, v.vertex );
o.uv = v.texcoord;
COMPUTE_EYEDEPTH(o.depth);
return o;
}
half4 frag_tree(v2f_uv i) : COLOR {
half4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a - 0.5 );
return DOFFactor(i.depth);
}
ENDCG
}
}
// terrain grass billboards
SubShader {
Tags { "RenderType"="GrassBillboard" }
Pass {
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_uv
#pragma multi_compile NO_INTEL_GMA_X3100_WORKAROUND INTEL_GMA_X3100_WORKAROUND
#include "UnityCG.cginc"
#include "TerrainEngine.cginc"
v2f_uv vert (appdata_grass v) {
v2f_uv o;
TerrainBillboardGrass(v.vertex, v.texcoord1.xy);
float waveAmount = v.texcoord1.y;
float4 dummyColor = 0;
TerrainWaveGrass (v.vertex, waveAmount, dummyColor, dummyColor);
o.pos = mul (glstate.matrix.mvp, v.vertex);
o.uv = v.texcoord;
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
// terrain grass non - billboards
SubShader {
Tags { "RenderType"="Grass" }
Pass {
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_uv
#pragma multi_compile NO_INTEL_GMA_X3100_WORKAROUND INTEL_GMA_X3100_WORKAROUND
#include "UnityCG.cginc"
#include "TerrainEngine.cginc"
v2f_uv vert (appdata_grass v) {
v2f_uv o;
float waveAmount = v.color.a * _WaveAndDistance.z;
float4 dummyColor = 0;
TerrainWaveGrass (v.vertex, waveAmount, dummyColor, dummyColor);
o.pos = mul (glstate.matrix.mvp, v.vertex);
o.uv = v.texcoord;
COMPUTE_EYEDEPTH(o.depth);
return o;
}
ENDCG
}
}
}
}
代码解释
属性部分:
_MainTex:基础纹理,初始值为白色纹理。_Cutoff:一个浮点型参数,用于裁剪操作,初始值为0.5。
结构体部分:
v2f:包含顶点位置和深度信息。v2f_uv:包含顶点位置、纹理坐标和深度信息。
DOFFactor函数: 该函数用于计算景深因子。通过传入的深度值
z,结合焦点距离focalDist和逆范围invRange,计算出与焦点的距离fromFocal,并根据其正负进行不同处理,最后通过saturate函数将结果限制在 [0, 1] 范围内。片段着色器部分:
frag:根据传入的深度信息计算景深因子并返回。frag_uv:先采样纹理,进行裁剪操作,然后根据深度信息计算景深因子并返回。
子着色器部分: 针对不同的渲染类型(如不透明对象、透明裁剪对象、地形树木和草地等),分别定义了不同的子着色器,每个子着色器包含一个或多个通道,通过不同的顶点和片段着色器处理不同类型对象的景深效果。
通过以上代码和解释,你可以在Unity中实现镜头景深效果。在实际使用时,可根据具体需求调整参数和代码逻辑。