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. C# 操作注册表WindowsRegistry

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsof ...

  2. This relative module was not found (转载)

    vue踩坑-This relative module was not found 在使用vue.js的日期选择插件 的时候,报错如下   This relative module was not fo ...

  3. C#程序实现软件开机自动启动的两种常用方法

    C#/WPF/WinForm/.NET程序代码实现软件程序开机自动启动的两种常用方法函数的示例与实例带详细注释 方法一:将软件的快捷方式创建到计算机的自动启动目录下(不需要管理员权限) 1.必要引用 ...

  4. Android Lifecycle使用

    引言 Lifecycle 是官方提供的架构组件之一,目前已经是稳定版本,Lifecycle 组件包括LifecycleOwner.LifecycleObserver.Lifecycle 组件是执行操作 ...

  5. Git学习(二)Git命令

    1.创建新的git仓库 初始化一个Git仓库,使用git init命令. 上图中我们新建了目录/home/honey/cxf,并进入目录cxf执行命令git init完成新git仓库的初始化,初始化成 ...

  6. Html5、css、JavaScript基础

    一.HTML学习 HTML样式Css 内联样式- 在HTML元素中使用"style" 属性 内部样式表 -在HTML文档头部 <head> 区域使用<style& ...

  7. js 时间戳转换为‘yyyy-MM-dd hh:mm’格式(es6语法)

    function formatDate(date,fmt) { if(/(y+)/.test(fmt)){ fmt = fmt.replace(RegExp.$1,(date.getFullYear( ...

  8. jQuery效果之封装模拟placeholder效果,让低版本浏览器也支持

    页面中的输入框默认的提示文字一般使用placeholder属性就可以了,即: <input type="text" name="username" pla ...

  9. Nginx 集群 反向代理多个服务器

    准备多个服务器,使用 nginx 先做好代理(我这里只有一台服务器,就拷贝两个 tomcat 了,端口分别设置为 8081 和 8082) 1,复制 tomcat cp -r apache-tomca ...

  10. 环信easeui集成:坑总结2018(二)

    环信EaseUI 集成,集成不做描述,看文档即可,下面主要谈一些对easeui的个性化需求修改. 该篇文章将解决的问题: 1.如何发送视频功能 2.未完待续.. ------------------- ...