unity shader 基础之十一 动画屏幕后处理深度纹理
Posted 路人张德帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity shader 基础之十一 动画屏幕后处理深度纹理相关的知识,希望对你有一定的参考价值。
11.1 时间变量
_Time,_SinTime,_CosTime,_unity_DeltaTime
11.2 纹理动画
一张贴图就是一张序列帧贴图,通过对uv偏移,获取不同uv下不同的图片
floor(x),获取小于x的最大整数
frac(x),获取x的小数部分
11.3 顶点动画
Disable Batching 标签,关闭合批,因为顶点动画是对单个顶点进行操作,合批会让多个单物体合并成一个物体,从而丢失了各自的模型空间
11.4 广告牌动画
广告牌的目的构建一个变化的基向量,也就是固定一个轴,从而计算出其它两个轴的坐标,根据这个基向量,计算出顶点变化后的位置,然后对图片采样
固定的轴向分为 法线或者向上的轴,法线就是摄像机位置-模型坐标的中心点位置
如果法线的y轴不为0,说明当前固定的是法线,然后通过法线和向上的位置叉乘得到向右的位置
12.1 屏幕后处理脚本系统
OnRenderImage(RT source,RT dest)
把当前画面渲染到source里面,然后对其应用指定的shader,赋值给dest,最终显示出来
Graphic.Blit(textureD source,RT dest)
12.2 增加屏幕对比度 、亮度、饱和度
12.3 边缘检测
边缘检测用的是卷积计算,重要的是选择合适的卷积核,把要计算的像素放在卷积核的中心,一次计算相邻像素的值,然后相加就是该像素的新值,该值就是相邻像素的对比值
每一个像素的新值,都要进行N*N次计算,N是卷积核的行列数
12.4 高斯模糊
算法:
12.5 Bloom 模糊
Bloom的原理:首先通过一个阈值,对屏幕图像提取一个亮度,存储到一个RT中,然后对该RT进行高斯模糊,然后和原图像进行混合
提取亮度:
和原图像混合:
13.1 获取深度和法线纹理
13.1.2 获取深度和法线纹理
urp 里面只有深度纹理,没有法线纹理
fload d=SAMPLE _DEPTH_TEXTURE(depthTex,uv):获取当前点的深度
SAMPLE_DEPTH_TEXTURE_PROJ(depthTex, UNITY_PROJ_COORD(scrPos))
上面的第二个参数是float3或者float4类型的,一般是前两个值除以第三个值之后,再进行采样,如果有第四个值,还会和第四个值进行比较
scrPos=ComputeScreenPos(i.pos)获取到的
通过采样得到的深度值,是映射之后的像素值,取值范围[0,1],所以NDC下的深度值也就是z/w=2d-1,取值范围[-1,1]
然后NDC下的深度值又等于
二者 结合得出
视角空间下的z:
上式=near*far/d*near+(1-d)far,以为d的取值范围是[0,1],所以 它的取值范围为[near,far]
是非线性的
如果要得到线性的,除以far,则上述为 near/d*near+(1-d)far,则范围[near/far,1],当near为0的时候,也就是近平面和摄像机重合时,取值就为[0,1]
float d=LinearEyeDepth(d):把采样得到的深度值,转换到视角空间下
float d=Linear01Depth(d):把采样得到的深度值,转换到线性空间下
如果要对 深度+法线纹理进行转换,unity提供的函数 DecodeDepthNormal(texel,out depth,out normal)
因为深度+法线纹理,法线存储在RG通道,深度存储在BA通道
解析深度的函数是
float d=DecodeFloatRG(uv.zw)
float n=DecodeViewNormalStereo(texel)
13.2 运动模糊,通过矩阵重建世界坐标
上图第一次画框的地方,我们的uv 就是NDC 坐标,只不过只有xy,所以经过对深度纹理采样,获得了NDC下的深度坐标z
然后反映射,得到裁剪空间下的坐标,也就是x,y,z,经过旋转矩阵之后得到了世界空间下的坐标,但是有一点是,世界空间下的w=1,所以除以w
13.3 全局雾效
开启雾效要使用#pragma multi_compile_fog
使用UNITY_FOG_COORDS, UNITY_TRANSFROM_FOG, UNITY_APPLY_FOG
上面重建世界坐标的方式,要在片元着色器中两次矩阵乘法,比较好性能,下面介绍一种
整体公式:
这里是线性深度,也就是从深度图中采样得到的深度
后面的interpolatedRay 是插值射线,也就是从摄像机到屏幕上一点的连线
下面有推导:
我们已知有图中的Near,depth,以及屏幕的宽高比(aspect),我们要求的向量是有图中的问号代表的欧式距离
先得到几个辅助向量:
上面的为什么要用camera.forward 乘以呢,是为了最后的结果是向量,halfHeight是个标量,我们要进行的是向量的运算
然后我们得到depth*interpolatedRay
根据三角形相似原则 得到 depth/?=near/TL
则 ?=depth * TL/near
提取出depth 则得到 interpolatedRay=TL/Near
因为四个角到摄像机的距离都相等,所以 TL是动态可换的,又因为最终我们得到的是向量的运算,所以采取的是单位向量*|Ray|,也就是 (TL/|TL|)* (|TL|/|Near|) 前边TL可以换成TR
然后把这个值传给片元着色器,根据差值得到某一点的射线向量
为什么只计算四个点就能知道某一点的射线向量呢?
因为我们的模型也就是抓取到的图像是一个面,只有四个顶点,也就是两个三角形,所以我们只需要处理好这四个点的向量,至于三角形面里面的,就在片元着色器进行差值得到了
下面是雾的计算:
以上是关于unity shader 基础之十一 动画屏幕后处理深度纹理的主要内容,如果未能解决你的问题,请参考以下文章
Unity3D Shader编程之十一 深入理解Unity5中的Standard Shader&屏幕像素化特效的实现
Unity Shader屏幕后处理3.0:均值模糊和高斯模糊
Visual C++游戏开发笔记之十一 基础动画显示 排序贴图
Visual C++游戏开发笔记之十一 基础动画显示 排序贴图