Getting the proper results to appear in the _CameraDepthTexture is fairly straightforward. If you’re using a surface shader it’s as easy as appending “addshadow” to the #pragma surface line. If you’re doing a vertex / frag shader you’ll need to add a custom shadow caster pass. There’s a basic shadow caster pass in Unity’s Vertex Fragment Shader Examples page.
Here’s the copy/paste of the relevant section:
// shadow caster rendering pass, implemented manually
// using macros from UnityCG.cginc
Pass
{
Tags {"LightMode"="ShadowCaster"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
float4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
That TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) looks scary, but it’s basically just taking the v.vertex and doing the usual mul(UNITY_MATRIX_MVP, v.vertex), with a couple extra things for shadow maps. All you need to do is do your custom vertex modifications prior to that macro and it will all work.
Example:
v2f vert(appdata_base v)
{
float4 worldPos = mul(_Object2World, v.vertex);
// do stuff to worldPos.xyz
v.vertex = mul(_World2Object, worldPos);
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
At this point you’re probably wondering what a shadow caster has to do with the depth. In forward rendering Unity doesn’t use the depth from the camera after it’s rendered the scene, but instead does a pre-pass rendering the entire view using those shadow caster shader passes and saves that as the _CameraDepthTexture, then it renders the camera view you actually see. This is why having ZWrite on or off on the main shader doesn’t seem to have any effect on what shows up in the depth texture, and why any custom vertex manipulations seem to do nothing. The Fallback line is where the shadow caster for most shaders comes from; if your shader doesn’t have a shadow caster pass it’ll use the one the Fallback shader uses instead.
Updating the depth / normals texture is a little more annoying, but basically you need a similar custom shader. Instead of using a special pass in your shader Unity uses the older replacement shader system to create the _CameraDepthNormalsTexture. The replacement shader in question is the Internal-DepthNormalsTexture.shader which you have to replace with your own shader with a new pass appended to it. Then your custom shader needs to have a custom “RenderType” tag and a matching “RenderType” shader in the Internal-DepthNormalsTexture.shader.
In Unity 5.3 and prior I don’t remember if you can get away with just adding a new Internal-DepthNormalsTexture.shader file into your assets folder or if you have to actually replace the one in the actual editor folder. If you’re using Unity 5.4 the graphics settings have an easy way to override this.
edit: Minor note about deferred for completeness sake. In the deferred the _CameraDepthTexture does come from the deferred camera’s depth pass, and the _CameraDepthNormalsTexture comes from the deferred normals and camera depth. However any forward rendered objects that you want to appear in the depth will use the same Shadow Caster pass to “inject” themselves into the deferred camera’s depth. They do not inject into the normals, and there is no way to fix this without actually using a deferred shader! This means fully forward rendered objects when using the deferred rendering path cannot work properly with any effect that needs the camera normals! The only solution is to render the object twice!