一 简介
1.1 啥是深度图
深度图通过获取观察视角中,物体由近到远的深度信息,来实现与其相关的特殊效果。
深度值是在像素信息中保存的[0,1]范围的非线性值,这些深度值来自裁剪坐标。Unity会自动利用Shader Replacement将RenderType为Opaque、渲染队列小于等于2500并且有ShadowCaster Pass的物体的深度值渲染到深度图中。
1.2 深度图可以实现的效果
- 垂直雾效
- 能量护盾
- 扫描线
- 卡通描边
- 运动模糊
- 等等
二 深度图的简单实现
2.1 获取像素深度信息
向前渲染和延迟渲染中获取深度信息的方式各有不同。
2.1.1【延迟渲染获取深度信息】
由于延迟渲染是先经过深度测试再处理灯光,所以像素缓冲区中已经有了深度信息。除了延迟渲染的相关设置外,无需任何多余设置即可直接在shader中使用
2.1.2【正向渲染获取深度信息】
在向前渲染中,必须先通过以下步骤用摄像机获取图像的像素与深度信息,才能在shader中使用
【步骤】新建c#脚本,将以下代码放置到脚本中,并将脚本赋给摄像机。
相机渲染图像后会调用脚本中的OnRenderImage方法。通过调用Graphics.Blit方法将已经渲染的RenderTexture source用指定或默认的shader pass处理并通过RenderTexture destination输出
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//需要Camera组件
[RequireComponent(typeof (Camera))]
public class cameraDepth : MonoBehaviour
{
public Material cameraMaterial;
void Start () {
Camera camera = gameObject.GetComponent<Camera> ();
//设置Camera的depthTextureMode,生成深度图
camera.depthTextureMode = DepthTextureMode.Depth;
}
//OnRenderImage在所有的渲染完成后调用
//该函数允许我们处理渲染后的图像,输入原图像source,输出的图像desitination
void OnRenderImage (RenderTexture source, RenderTexture destination){
//如果指定了cameraMaterial 就用cameraMaterial处理输出的图像,否则就用输入的原图像用作输出
if (cameraMaterial != null)
{
//该方法用于将输入的图像指定material和shader pass 后输出
Graphics.Blit(source, destination, cameraMaterial);
}
else
{
Graphics.Blit(source, destination);
}
}
}
2.2 Shader中使用深度信息
新建Shader脚本,将以下代码放置到脚本中。新建Material并指定好刚刚新建的Shader,赋给物体
Shader "Custom/Depth" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass{
CGPROGRAM
// 定义顶点、片片渲染器,并引入shader相关的宏
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 声明贴图变量,用于接受摄像机的贴图
sampler2D _CameraDepthTexture;
// 片元渲染器的输入结构
struct v2f {
// 像素的坐标
float4 pos : SV_POSITION;
float3 uv:TEXCOORD0;
// 屏幕坐标
float4 screenPos:TEXCOORD1;
};
//顶点渲染器
v2f vert (appdata_base v){
v2f o;
// 将顶点坐标模型空间转为裁剪空间
o.pos = UnityObjectToClipPos (v.vertex);
// 使用ComputeScreenPos计算出屏幕坐标
// 输入裁剪空间的位置,获取齐次空间的屏幕坐标。(不是最终输出的屏幕坐标)
o.screenPos = ComputeScreenPos(o.pos);
o.uv = v.texcoord;
return o;
}
//片元渲染器
half4 frag (v2f i) : COLOR{
// 计算出投影纹理坐标
half4 proj =UNITY_PROJ_COORD(i.screenPos);
//tex2D和tex2Dproj的区别在于:tex2Dproj会先将第二个参数除以它的最后一个分量。
//要想进行深度值对比,只有先存储深度值。在生成ShadowMap时存储深度值,然后无论用tex2D还是tex2Dproj都可以得到深度值。
half4 _tex2Dproj = tex2Dproj(_CameraDepthTexture, proj);
//LinearEyeDepth负责把深度纹理的采样结果转换到视角空间下的深度值
//Linear01Depth则返回一个范围在[0,1]的线性深度值
half depthValue = Linear01Depth(_tex2Dproj.r);
// float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
// float depthValue = Linear01Depth(depth);
return half4(depthValue, depthValue, depthValue, 1);
}
ENDCG
}
}
// 这个必须要有。失败的时候尝试调用Diffuse subshader
FallBack "Diffuse"
}
就完成了
版权声明:本文为lengyoumo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。