Unity提供了很多Image Effect效果,包含Global Fog、DOF、Boom、Blur、Edge Detection等等,这些效果里面都会使用到摄像机深度或者根据深度还原世界坐标实现各种效果,这篇文章主要介绍Unity中获取相机深度的方式。

1. Camera Image Effect

Image Effect是Post Effect中的一种方式,Camera GameObject脚本上挂在脚本带有OnImageRender来实现, 具体实现参考Unity官网说明.

对于深度纹理,相机需设置DepthTextureMode参数,可设置为DepthTextureMode.Depth或者DepthTextureMode.DepthNormals,配合unity shaderLab中提供的参数_CameraDepthTexture 或者_CameraDepthNormalsTexture来获取。

2. 深度纹理

深度纹理并非深度缓冲中的数据,而是通过特定Pass获得

DepthTextureMode.Depth

Unity4.X和Unity5.X版本的实现方式不太一样,Unity4.X通过"RenderType" 标签通过Camera Shader 替换获取,Unity5通过ShadowCaster Pass获取,Unity5官方文档描述:

Depth texture is rendered using the same shader passes as used for shadow caster rendering (ShadowCaster pass type). So by extension, if a shader does not support shadow casting (i.e. there’s no shadow caster pass in the shader or any of the fallbacks), then objects using that shader will not show up in the depth texture.

Make your shader fallback to some other shader that has a shadow casting pass, or If you’re using surface shaders, adding an addshadow directive will make them generate a shadow pass too.

Note that only “opaque” objects (that which have their materials and shaders setup to use render queue <= 2500) are rendered into the depth texture.

对于自身带有ShadowCaster Pass或者FallBack中含有,并且Render Queue小于等于2500的渲染对象才会出现在深度纹理中,详细的测试可以参考:【Unity Shader】Shadow Caster、RenderType和_CameraDepthTexture

在Shader中,需提前定义纹理_CameraDepthTexture ,为了兼容不同的平台,Unity ShaderLab提供了UNITY_SAMPLE_DEPTH、SAMPLE_DEPTH_TEXTURE方法解决这个问题。

   Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//提前定义
uniform sampler2D_float _CameraDepthTexture;
struct uinput
{
float4 pos : POSITION;
};
struct uoutput
{
float4 pos : SV_POSITION;
}; uoutput vert(uinput i)
{
uoutput o;
o.pos = mul(UNITY_MATRIX_MVP, i.pos);
return o;
} fixed4 frag(uoutput o) : COLOR
{
//兼容问题
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
depth = Linear01Depth(depth) * 10.0f;
return fixed4(depth,depth,depth,1);
}
ENDCG
DepthTextureMode.DepthNormals

带有Normals和depth 的的32位贴图,Normals根据Stereographic projection编码到R&G通道,Depth通过映射编码到 B&A 通道。Unity ShaderLab也提供DecodeDepthNormal 方法惊醒解码,其中深度是0~1范围

Normals & Depth Texture 是通过Camera Shader replacement实现,可以将RenderType为:Opaque、TransparentCutout、TreeBark、TreeLeaf、TreeOpaque、TreeTransparentCutout、TreeBillboard、GrassBillboard、Grass类型才会进行深度渲染,对于Transparent\AlphaTest是不会渲染到这个纹理中。详情可参考:浅析Unity shader中RenderType的作用及_CameraDepthNormalsTexture

在使用中,需提前定义_CameraDepthNormalsTexture,使用DecodeDepthNormal解码,需要注意的是:深度是0~1范围,和_CameraDepthTexture 有区别

3. 自定义深度纹理

对于透明物体,上面两种方式都不能很好的获得深度纹理,比如说在以水为主的场景中,这两种方式获得的结果都不是太理想(尝试 unity自带水的例子)。 这种情况下,可以通过类似_CameraDepthNormalsTexture实现方式,自定义深度sheader,通过Camera Shader replacement方式采集深度。

shader部分

Shader "Custom/CopyDepth" {
Properties {
_MainTex ("", 2D) = "white" {}
_Cutoff ("", Float) = 0.5
_Color ("", Color) = (1,1,1,1)
} SubShader {
Tags { "RenderType"="Transparent" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
float4 nz : TEXCOORD0;
};
v2f vert( appdata_base v )
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.nz.xyz = COMPUTE_VIEW_NORMAL;
o.nz.w = COMPUTE_DEPTH_01;
return o;
} fixed4 _Color;
fixed4 frag(v2f i) : SV_Target
{
//clip(_Color.a-0.01);
return EncodeDepthNormal (i.nz.w, i.nz.xyz);
}
ENDCG
}
}
Fallback Off
}

脚本部分

using UnityEngine;
using System.Collections; [RequireComponent(typeof (Camera))]
public class CustomDepth : MonoBehaviour
{
public GameObject depthCamObj; private Camera mCam;
private Shader mCustomDepth;
private Material mMat;
private RenderTexture depthTexture; private Shader mCopyShader ;
void Awake()
{
mCam = GetComponent<Camera>(); mCustomDepth = Shader.Find("Custom/CustomDepth");
mCopyShader = Shader.Find("Custom/CopyDepth");
mMat = new Material(mCustomDepth); // mCam.SetReplacementShader(Shader.Find("Custom/CopyDepth"), "RenderType");
} //可优化
internal void OnPreRender()
{
if (depthTexture)
{
RenderTexture.ReleaseTemporary(depthTexture);
depthTexture = null;
}
Camera depthCam;
if (depthCamObj == null)
{
depthCamObj = new GameObject("DepthCamera");
depthCamObj.AddComponent<Camera>();
depthCam = depthCamObj.GetComponent<Camera>();
depthCam.enabled = false;
// depthCamObj.hideFlags = HideFlags.HideAndDontSave;
}
else
{
depthCam = depthCamObj.GetComponent<Camera>();
} depthCam.CopyFrom(mCam);
depthTexture = RenderTexture.GetTemporary(mCam.pixelWidth, mCam.pixelHeight, 16, RenderTextureFormat.ARGB32);
depthCam.backgroundColor = new Color(0, 0, 0, 0);
depthCam.clearFlags = CameraClearFlags.SolidColor; ;
depthCam.targetTexture = depthTexture;
depthCam.RenderWithShader(mCopyShader, "RenderType");
mMat.SetTexture("_DepthTexture", depthTexture);
} void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (null != mMat)
{
Graphics.Blit(source, destination, mMat);
}
else
{
Graphics.Blit(source, destination);
}
} }



Shader中采集了Normals & Depth Texture ,当然也可以只写Depth Texture。其中只实现了RenderType=Transparent的类型,当然也可以添加其他RenderType类型,具体可以参考Unity Shader源码文件“Hidden/Camera-DepthNormalTexture”。脚本只是测试使用,具体还需优化。

4. 小结

当然也可以在自己的shader中单独定义一个Pass来获得深度纹理,不同再去依赖Unity自身的实现方式(避免Unity升级的各种蛋疼)。

使用中,ShaderLab也提供一些其他方法:Linear01Depth() 、LinearEyeDepth()等(可参考Unity源码UnityCG.cginc)等。还需要注意在不同平台的差异,可以参考官方说明中关于深度的部分:https://docs.unity3d.com/Manual/SL-PlatformDifferences.html

Unity Effect资源包中提供各种各样的效果,可以用于学习。

5. 参考

官方文档

如何采集深度

定制自己的 Depth Texture

相机深度纹理

Unity Shaders – Depth and Normal Textures (Part 3)

Unity Shader 基础(3) 获取深度纹理的更多相关文章

  1. Unity Shader 基础(4) 由深度纹理重建坐标

    在PostImage中经常会用到物体本身的位置信息,但是Image Effect自身是不包含这些信息的,因为屏幕后处其实是使用特定的材质渲染一个刚好填满屏幕的四边形面片(四个角对应近剪裁面的四个角). ...

  2. Unity Shader基础

    Unity Shader基础 先上代码,代码一般是这样的. void Initialization(){ //先从硬盘加载代码再加载到GPU中 string vertexShaderCode = Lo ...

  3. Unity Shader 基础

    推荐: https://www.cnblogs.com/nanwei/p/7277417.html 上面链接作者的整个系列都写的不错 https://www.cnblogs.com/nanwei/ca ...

  4. Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...

  5. 第二章 Unity Shader基础

    [TOC] 1. Unity Shader 的基础: ShaderLab 学习和编写着色器的过程一直是一个学习曲线很陡峭的过程,通常情况下为了自定义渲染效果往往要和很多文件和设置打交道,这些设置很容易 ...

  6. 【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现

    笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...

  7. Unity Shader 基础(1): RenderType & ReplacementShader

    很多Shader中都会定义RenderType这个类型,但是一直搞不明白到底是干嘛的,官方文档是这样结解释的:Rendering with Replaced Shaders Rendering wit ...

  8. Unity Shader基础(1):基础

    一.Shaderlab语法 1.给Shader起名字 Shader "Custom/MyShader" 这个名称会出现在材质选择使用的下拉列表里 2. Properties (属性 ...

  9. [Unity] Shader(着色器)之纹理贴图

    在Shader中,我们除了可以设定各种光线处理外,还可以增加纹理贴图. 使用 settexture 命令可以为着色器指定纹理. 示例代码: Shader "Sbin/ff2" { ...

随机推荐

  1. samba企业级实战应用详解-技术流ken

    1.简介 Samba是一套使用SMB(Server Message Block)协议的应用程序, 通过支持这个协议, Samba允许Linux服务器与Windows系统之间进行通信,使跨平台的互访成为 ...

  2. 匿名函数python内置高阶函数以及递归

    匿名函数 python定义一个函数通常使用def关键词,后面跟函数名,然后是注释.代码块等. def func(): '''注释''' print('from func') 这样就在全局命名空间定义了 ...

  3. 所有人都可以是开发人员——《Office 365开发入门指南》视频教程即将上市

      今天是春节假期的最后一天,在这里给全国的朋友们拜个晚年,祝大家身体健康,晚年幸福啊.这个春节大家过的怎么样啊,我自己是在老家过的年,家乡的年味还是比较浓的,也再次感谢朋友圈的大家给我看了各地的风光 ...

  4. 【Oracle 11gR2】静默安装 db_install.rsp文件详解

    #################################################################### ## Copyright(c) Oracle Corporat ...

  5. 【Java每日一题】20170327

    20170324问题解析请点击今日问题下方的“[Java每日一题]20170327”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...

  6. Flask 系列之 SQLAlchemy

    SQLAlchemy 是一种 ORM 框架,通过使用它,可以大大简化我们对数据库的操作,不用再写各种复杂的 sql语句 了. 说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环 ...

  7. 剑指offer:1.找出数组中重复的数(java版)

    数组中重复的数:题目:找出数组中重复的数,题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内.数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任 ...

  8. HTML5标签选择,图文混排使用dl dt dd

    图文混排,可以使用 dl dt dd(dd 和 dt 是同级,不可以嵌套,没有先后顺序) 1,上面红色部分是标题,可以使用h1里面包含一个span标签,样式一样,所以两个可以一起写. 2,上面黑色部分 ...

  9. adb for mac

    1.Install homebrew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/mas ...

  10. CSS3动画属性:转换(transition)

    W3C标准中对css3的transition这是样描述的:“css的transition允许css的属性值在一定的时间区间内平滑地过渡.这种效果可以在鼠标单击.获得焦点.被点击或对元素任何改变中触发, ...