

简单的利用屏幕深度特效
上一篇一键说了屏幕颜色的获取,这一篇学习一下屏幕深度的内容,这里写了一个简单的特效,该特效在unity里很常见了,会连连看的童鞋分分钟能搞定。这里在urp里手写一遍加深理解。
第一步,我们要获取屏幕uv。上一篇里讲了三种方式获取,而当时使用了第三种最简单的方式;该篇我们采取第二种------手动计算一遍屏幕uv。在顶点着色器里,计算屏幕uv,并把xy存储为未经透除的uv通道,zw正常存储。

顶点着色器里计算屏幕uv
在片元着色器里进行透视除法,在检测一下平台矫正uv。这样我们就能得到正常的uv,当然如果你嫌弃这种方式麻烦,可以使用上一篇的方式获得屏幕uv。

屏幕uv的计算
第二步,拿到0-1线性的屏幕深度图。管线配置文件里要打开深度图,然后shader里采样这张图,这张深度图的名字是_CameraDepthTexture。

采样深度图
然后在顶点着色器里用屏幕uv去采样这张图,并用float Linear01Depth(float depth, float4 zBufferParam)函数去把它变换成线性深度图。

得到正常的深度缓冲的图
该函数定义在Common.hlsl里,注意它和build in的同名函数的参数不同,请注意。

深度图变换到0-1的线性深度函数
第三步,拿到模型像素在线性0-1的深度值。这个比较简单,直接取片元着色器里的HClip的Z分量,再次使用上面的函数即可得到正常深度。

得到模型像素的深度
把模型深度在和屏幕深度图相减,进行一些加减乘除手动微调,即可得到和场景模型接触的效果。

接触效果
第四步,计算一个菲涅尔,可以使用“入门精要”的公式计算,这里本人弄了个山寨版的,效果还行。

随意计算的菲涅尔,公式并不完全准确

山寨菲尼尔
第五步,计算扫光效果,利用世界坐标的y轴作为“uv”的滚动效果,这是本人在连连看里经常使用的一个公式,如果读者看不懂公式也没关系,可以手动在连连看里还原一下看看效果。

利用世界坐标制作扫光效果

光带会缓慢从下向上滚动,类型滚uv
第六步,采样一下主纹理,本人是在百度上搜了一张图,在ps里小修了一下拿来用。

百度随便找的一张图然后ps修了一下
把它贴到球上,调整一下tile,shader里顺便滚一下uv。

采样的时候滚uv
最后把它们全部加到一起,小特效就做出来了。

本篇的内容重点并不是特效本身,而是如果获取屏幕深度并把它转到线性空间里,同时也说明了一下如何获取模型像素的线性深度值。有时候在水体的制作里也会用到:它和岸边的交界线的制作原理也是一致的,通过他可以做一些水体和岸,水中裸露的石头的交互;在配合上一篇的屏幕空间颜色来得到折射效果;在采样一下反射球/天空盒来得到反射效果;配合一下菲涅尔,来点法线的滚uv,(如果可以再来点去曲面细分+快速傅里叶变换的顶点动画)就可以做出一个漂亮的水体效果了。不吹了,再吹牛下去就吹不动了,下面附源码,直接复制时,若出现报错,是每行代码前面的空格错误,删掉即可。
该篇完成后,下一篇的内容将是URP的自定义后处理。
Shader "WX/URP/depth"
{
Properties
{
_MainTex("MainTex",2D)="white"{}
_BaseColor("BaseColor",Color)=(1,1,1,1)
_depthoffset("depthoffset",float)=1
[HDR]_emissioncolor("EmissionColor",Color )=(1,1,1,1)
}
SubShader
{
Tags{
"RenderPipeline"="UniversalRenderPipeline"
"Queue"="Transparent"
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
//#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
//#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
//#pragma shader_feature_local _ADDLIGHT_ON
//#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
//#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
//#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
//#pragma multi_compile _ _SHADOWS_SOFT
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
half4 _BaseColor;
float _depthoffset;
float4 _emissioncolor;
CBUFFER_END
TEXTURE2D( _MainTex);
SAMPLER(sampler_MainTex);
SAMPLER(_CameraDepthTexture);
struct a2v
{
float4 positionOS:POSITION;
float4 normalOS:NORMAL;
float2 texcoord:TEXCOORD;
};
struct v2f
{
float4 positionCS:SV_POSITION;
float2 texcoord:TEXCOORD;
float4 sspos:TEXCOORD2;
float3 positionWS:TEXCOORD3;
float3 normalWS:TEXCOORD4 ;
};
ENDHLSL
pass
{
Tags{
"LightMode"="UniversalForward"
"RenderType"="Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex VERT
#pragma fragment FRAG
v2f VERT(a2v i)
{
v2f o;
o.positionCS=TransformObjectToHClip(i.positionOS.xyz);
o.texcoord=TRANSFORM_TEX(i.texcoord,_MainTex);
//屏幕坐标sspos,xy保存为未透除的屏幕uv,zw不变
o.sspos.xy=o.positionCS.xy*0.5+0.5*float2(o.positionCS.w,o.positionCS.w);
o.sspos.zw=o.positionCS.zw;
o.positionWS=TransformObjectToWorld(i.positionOS.xyz);
o.normalWS=normalize(TransformObjectToWorldNormal(i.normalOS.xyz));
return o;
}
half4 FRAG(v2f i):SV_TARGET
{
float2 uv=i.texcoord;
uv.x+=_Time.y*0.2;//滚uv,以每秒钟滚0.2圈的速度旋转
half4 tex=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,uv)*_BaseColor;
//开始计算屏幕uv
i.sspos.xy/=i.sspos.w;//透除
#ifdef UNITY_UV_STARTS_AT_TOP//判断当前的平台是openGL还是dx
i.sspos.y=1-i.sspos.y;
#endif//得到正常的屏幕uv,也可以通过i.positionCS.xy/_ScreenParams.xy来得到屏幕uv
//计算(山寨简化版)菲涅尔
float3 WSview=normalize(_WorldSpaceCameraPos-i.positionWS);
float fre=(1-dot(i.normalWS,WSview))*_depthoffset;
//计算缓冲区深度,模型深度
float4 depthcolor= tex2D(_CameraDepthTexture,i.sspos.xy);
float depthbuffer=Linear01Depth(depthcolor,_ZBufferParams);//得到线性的深度缓冲
//计算模型深度
float depth=i.positionCS.z;
depth=Linear01Depth(depth,_ZBufferParams);//得到模型的线性深度
float edge= saturate(depth-depthbuffer+0.005)*100*_depthoffset;//计算接触光
//return edge;
//计算扫光,这步看不懂建议用连连看还原,这是一个做特效的通用公式
float flow=saturate( pow(1-abs(frac(i.positionWS.y*0.3-_Time.y*0.2)-0.5),10)*0.3);
float4 flowcolor=flow*_emissioncolor;
//return flowcolor*2;
return float4(tex.xyz,edge+fre)+flowcolor;
}
ENDHLSL
}
}
}