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. IIS应用程序池_缓存回收

    本人最近由于公司业务,需要把问卷的问题和答案存入缓存中已提高问卷加载速度,减少数据库压力. 缓存关键代码(公司代码已做封装,这里只贴出关键代码): HttpRuntime.Cache.Insert(k ...

  2. [转]图解Docker容器和镜像

    本文转自:https://www.cnblogs.com/wangqiaomei/p/5818636.html 图解Docker容器和镜像 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器 ...

  3. SET XACT_ABORT ON [SQL SERVER] 设置事务全部回滚

    SET XACT_ABORT ON 设置事务回滚的默认是OFF. 当为ON时,如果你存储中的某个地方出了问题,整个事务中的语句都会回滚为OFF时,只回滚错误的地方

  4. C# Json反序列化

    Json反序列化有两种方式[本人],一种是生成实体的,方便处理大量数据,复杂度稍高,一种是用匿名类写,方便读取数据,较为简单. 使用了Newtonsoft.Json,可以自行在nuget中导入 Jso ...

  5. 工作笔记-table问题汇总(vue单文件组件)

    1.vue: computed里定义的数据,在其他地方不能再重新赋值,会报错: Computed property "xxxxxx" was assigned to but it ...

  6. laravel接值 get post

    laravel使用一种简单的方式来访问用户提交的信息. 你可以用统一的方式来访问用户提交的信息,而不用为用户提交信息的方式操心. 引用类:use Illuminate\Support\Facades\ ...

  7. canvas学习笔记之2d画布基础的实现

    一. Canvas是啥 < canvas > 是一个可以使用脚本(通常是js)来绘图的HTML元素 < canvas > 最早由Apple引入WebKit,用于Mac OS X ...

  8. layui table 表格模板按钮实例

    这是个是全部的jsp 页面: <%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8& ...

  9. layui layer select 选择被遮挡

    在编程的时候, layer弹窗中的select 经常会遇到被遮挡的情况: 解决方法:在页面里面找到对应div的class 给overflow新的属性visible即可(默认值.内容不会被修剪,会呈现在 ...

  10. 搞清Image加载事件(onload)、加载状态(complete)后,实现图片的本地预览,并自适应于父元素内(完成)

    onload与complete介绍 complete只是HTMLImageElement对象的一个属性,可以判断图片加载完成,不管图片是不是有缓存:而onload则是这个Image对象的load事件回 ...