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. OJ:又一道考察多态的题目

    Description 下面的程序输出结果是: A::Fun A::Do A::Fun C::Do 请填空: 程序代码如下 #include <iostream> using namesp ...

  2. [转]认识JWT

    本文转自:https://www.cnblogs.com/cjsblog/p/9277677.html 1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准 ...

  3. C#操作DbConnection类

    一.常用属性 名称 说明 ConnectionString 获取或设置用于打开数据库的字符串.(重写 DbConnection.ConnectionString) ConnectionTimeout ...

  4. 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略

    垃圾收集器与内存分配策略 详解 3.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第三章 ,为了整理思路,简单记录一下,方便后期查阅. 3.2 对象已死吗 在垃圾收集器进行回收 ...

  5. JQuery官方学习资料(译):$( document ).ready()

         一个页面直到document是”ready“才能被安全的操作,Jquery为你检查这种状态.代码包含在$( document ).ready()的内部将会仅仅运行一次在页面Document ...

  6. 深入理解JAVA中的NIO

    前言: 传统的 IO 流还是有很多缺陷的,尤其它的阻塞性加上磁盘读写本来就慢,会导致 CPU 使用效率大大降低. 所以,jdk 1.4 发布了 NIO 包,NIO 的文件读写设计颠覆了传统 IO 的设 ...

  7. python面向对象学习(二)基本语法

    目录 1. dir内置函数 2. 定义简单的类(只包含方法) 2.1 定义只包含方法的类 2.2 创建对象 2.3 编写第一个面向对象程序 3. 方法中的self参数 3.1 案例改造 -- 给对象添 ...

  8. linux的 .bashrc文件是干什么的?

    使用man bash命令查看到的联机帮助文件中的相关解释如下: .bashrc - The individual per-interactive-shell startup file. 这个文件主要保 ...

  9. Python3 系列之 可变参数和关键字参数

    刚开始接触 python 的时候,对 python 中的 *wargs (可变参数) 和 **kwargs (关键字参数)的理解不是很透彻,看了一下 <Explore Python>一书, ...

  10. JavaScript黑客是这样窃取比特币的,Vue开发者不用担心!

    如果你是JavaScript或者区块链开发者,如果你有关注区块链以及比特币,那么你应该听说了比特币钱包Copay被黑客攻击的事情.但是,你知道这是怎么回事吗? 总结 比特币钱包copay依赖event ...