1、 在Unity中,要得到深度缓存(Depthbuffer),就需要用到一个RenderTexture纹理。
2、 深度缓存,或者深度纹理,其实就是一个包含有场景里物体离照相机的距离值的一张纹理图。
3、 为了让摄像机生成一张深度纹理,只需要设置Camera.depthTextureMode即可。但这个时候生成了纹理,还需要我们去获取。所以我们需要把它传到一个shader中,于是就用到OnRenderImage这个函数。
于是我们得出下面一个例子:
using UnityEngine;
using System.Collections;
//so that we can see changes we make without having to run the game
[ExecuteInEditMode]
public class PostProcessDepthGrayscale : MonoBehaviour {
public Material mat;
void Start () {
//设置Camera的depthTextureMode,使得摄像机能生成深度图。
Camera.main.depthTextureMode = DepthTextureMode.Depth;
}
void OnRenderImage (RenderTexture source, RenderTexture destination){
Graphics.Blit(source,destination,mat);
//mat就是包含shader的一个材质球,而这个shader就是我们要把
//destination这个render纹理传进去的shader。Shader的写法如下所示。
}
}
接下来这个shader代码如下:
Shader "Custom/DepthGrayscale" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _CameraDepthTexture;
struct v2f {
float4 pos : SV_POSITION;
float4 scrPos:TEXCOORD1;
};
//Vertex Shader
v2f vert (appdata_base v){
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.scrPos=ComputeScreenPos(o.pos);
//for some reason, the y position of the depthtexture comes out inverted
//o.scrPos.y = 1 - o.scrPos.y;
return o;
}
//Fragment Shader
half4 frag (v2f i) : COLOR{
float depthValue =Linear01Depth (tex2Dproj(_CameraDepthTexture,UNITY_PROJ_COORD(i.scrPos)).r);
half4 depth;
depth.r = depthValue;
depth.g = depthValue;
depth.b = depthValue;
depth.a = 1;
return depth;
}
ENDCG
}
}
FallBack "Diffuse"
}
前面都好理解,而且需要注意的是,_CameraDepthTexture这个变量的值是Unityshader内部传进去的。
float depthValue =Linear01Depth (tex2Dproj(_CameraDepthTexture,UNITY_PROJ_COORD(i.scrPos)).r);
Linear01Depth这个是将其中的值转换成深度的0~1之间的值,tex2Dproj采样得到的颜色值为何只取r值,而且取g、b值是全黑的。这需要再考虑一下。(对于这个问题,现测得RenderTexture如果它的Format改成Depth的话,就只有红色这一个通道颜色了。所以会出现上面的这个情况。)
而且,这里的深度是受RenderQueue的值的影响,并不只z轴坐标。比如你的RenderQueue=3000,但是z轴坐标离摄像机很近,那它的深度值也是很大的。得到一幅深度图如下图:
可见,离摄像机越近,深度越小,颜色值越深。