unity实现镜头景深效果

2015年01月21日 11:58 0 点赞 0 评论 更新于 2025-11-21 15:00

在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
}
}
}
}

代码解释

  1. 属性部分

    • _MainTex:基础纹理,初始值为白色纹理。
    • _Cutoff:一个浮点型参数,用于裁剪操作,初始值为0.5。
  2. 结构体部分

    • v2f:包含顶点位置和深度信息。
    • v2f_uv:包含顶点位置、纹理坐标和深度信息。
  3. DOFFactor函数: 该函数用于计算景深因子。通过传入的深度值 z,结合焦点距离 focalDist 和逆范围 invRange,计算出与焦点的距离 fromFocal,并根据其正负进行不同处理,最后通过 saturate 函数将结果限制在 [0, 1] 范围内。

  4. 片段着色器部分

    • frag:根据传入的深度信息计算景深因子并返回。
    • frag_uv:先采样纹理,进行裁剪操作,然后根据深度信息计算景深因子并返回。
  5. 子着色器部分: 针对不同的渲染类型(如不透明对象、透明裁剪对象、地形树木和草地等),分别定义了不同的子着色器,每个子着色器包含一个或多个通道,通过不同的顶点和片段着色器处理不同类型对象的景深效果。

通过以上代码和解释,你可以在Unity中实现镜头景深效果。在实际使用时,可根据具体需求调整参数和代码逻辑。

作者信息

feifeila

feifeila

共发布了 3994 篇文章