博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity Shader 基础(3) 获取深度纹理
阅读量:6403 次
发布时间:2019-06-23

本文共 5825 字,大约阅读时间需要 19 分钟。

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

1. Camera Image Effect

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

对于深度纹理,相机需设置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的渲染对象才会出现在深度纹理中,详细的测试可以参考:

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

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 是通过实现,可以将RenderType为:Opaque、TransparentCutout、TreeBark、TreeLeaf、TreeOpaque、TreeTransparentCutout、TreeBillboard、GrassBillboard、Grass类型才会进行深度渲染,对于Transparent\AlphaTest是不会渲染到这个纹理中。详情可参考:

在使用中,需提前定义_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
(); 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
(); depthCam = depthCamObj.GetComponent
(); depthCam.enabled = false; // depthCamObj.hideFlags = HideFlags.HideAndDontSave; } else { depthCam = depthCamObj.GetComponent
(); } 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); } }}

mark

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)等。还需要注意在不同平台的差异,可以参考官方说明中关于深度的部分:

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

5. 参考

转载于:https://www.cnblogs.com/zsb517/p/6655546.html

你可能感兴趣的文章
Golang性能调优入门
查看>>
sqlloader外部表
查看>>
golang笔记——数组与切片
查看>>
屏蔽可忽略的js脚本错误
查看>>
散文分享
查看>>
【Vue】vue.js常用指令
查看>>
NFS学习
查看>>
MySql常用命令总结
查看>>
又一年...
查看>>
文件上传框的美化+预览+ajax
查看>>
Linux VFS
查看>>
ext不能选中复制属性_如何实现Extjs的grid单元格只让选择(即可以复制单元格内容)但是不让修改?...
查看>>
python中print的作用*8、不能+8_在 Python 3.x 中语句 print(*[1,2,3]) 不能正确执行。 (1.0分)_学小易找答案...
查看>>
python 生成html代码_使用Python Markdown 生成 html
查看>>
axure如何导出原件_Axure 教程:轻松导出图标字体所有图标
查看>>
laravel input值必须不等于0_框架不提供,动手造一个:Laravel表单验证自定义用法...
查看>>
cad填充图案乱理石_太快了吧!原来大神是这样用CAD图案填充的
查看>>
activator.createinstance 需要垃圾回收么_在垃圾回收器中有哪几种判断是否需要被回收的方法...
查看>>
rocketmq 消息指定_RocketMQ入坑系列(一)角色介绍及基本使用
查看>>
redis zset转set 反序列化失败_掌握好Redis的数据类型,面试心里有底了
查看>>