Skip to content

Instantly share code, notes, and snippets.

@stilllisisi
Created March 11, 2020 08:56
Show Gist options
  • Save stilllisisi/502dee44ec3821548e521395f36116cf to your computer and use it in GitHub Desktop.
Save stilllisisi/502dee44ec3821548e521395f36116cf to your computer and use it in GitHub Desktop.
【游戏-unity】Unity Shader基础:获取深度纹理。Unity提供了很多Image Effect效果,包含Global Fog、DOF、Boom、Blur、Edge Detection等等,这些效果里面都会使用到摄像机深度或者根据深度还原世界坐标实现各种效果,这篇文章主要介绍Unity中获取相机深度的方式。
//1、深度纹理
//深度纹理并非深度缓冲中的数据,而是通过特定Pass获得: DepthTextureMode.Depth
//Unity4.X和Unity5.X版本的实现方式不太一样,Unity4.X通过"RenderType" 标签通过Camera Shader 替换获取;
//Unity5通过ShadowCaster Pass获取, 对于自身带有ShadowCaster Pass或者FallBack中含有,并且Render Queue小于等于2500的渲染对象才会出现在深度纹理中.
//shader代码:
//在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
//2、自定义深度纹理
//脚本部分:
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”。脚本只是测试使用,具体还需优化。
//2、自定义深度纹理
//对于透明物体,上面方式不能很好的获得深度纹理,比如说在以水为主的场景中。这种情况下,可以通过类似_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
}
@stilllisisi
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment