unity震屏插件拖到相机属性下的时候提示脚本错误,怎么解决?

前言废话依旧比较多,感觉我是个写游戏体验评测的,233。最近想起了《恶灵附身》这款游戏的几个效果:

《恶灵附身》整款游戏都是在一个“疯子”撸总的脑洞世界里面,游戏内容相当恐怖(吓得我当年一边尖叫一边玩,不光把我吓够呛,把我室友也吓坏了),有“贞子”,“保险箱怪”等等至今让我久久不能忘怀的Boss,不过整个游戏既有恐怖的地方,又有刺激的战斗,非常符合三上真司一贯的作风(我是三上生化危机系列的铁粉,哇咔咔),可惜《恶灵附身2》玩法有点转型,类似《丧尸围城》了,前半段很好,后半段不知是否是经费不足,感觉整体不如前半段好。不过还是很期待续作的。

既然整款游戏都是在脑洞世界里面,所以整个游戏的过程完全不按照常理出牌,可能前一秒还在平静的医院走廊,下一秒直接就直接切换到满是怪物的场景。整个游戏里面大量运用了各种好玩的效果,上面的屏幕扭曲,屏幕扫描波,高度雾效(个人感觉《恶灵附身》里面的应该是特效做的,不过本文的实现方式不太一样罢了)就都其中之一,今天主要是来整理一波深度图的各种知识点,然后做几个好玩的效果。

深度是个好东西哇,很多效果都需要深度,比如,屏幕空间扫描效果,软粒子,阴影,SSAO,近似次表面散射(更确切的说是透射),对于延迟渲染来说,还可以用深度反推世界空间位置降低带宽消耗,还可以用深度做运动模糊,屏幕空间高度雾,距离雾,部分也都需要深度,可以说,深度是一些渲染高级效果必要的条件。另一方面,光栅化渲染本身可以得到正确的效果,就与深度(Z Buffer)有着密不可分的关系。

深度对于实时渲染的意义十分重大,OpenGL,DX,Unity为我们封装好了很多深度相关的内容,如ZTest,ZWrite,CameraDepthMode,Linear01Depth等等。今天我来整理一下与学习过程中遇到的深度相关的一些问题,主要是渲染中深度的一些问题以及Unity中深度图生成,深度图的使用,深度的精度,Reverse-Z等等问题,然后再用深度图,实现一些好玩的效果。本人才疏学浅,如果有不正确的地方,还望各位高手批评指正。

在渲染中为了保证渲染的正确,其实主要得益于两个最常用的算法,第一个是画家算法。所谓画家算法,就是按照画画的顺序,先画远处的内容,再画近处的内容叠加上去,近处的会覆盖掉远处的内容。即,在绘制之前,需要先按照远近排序。但是画家算法有一个很严重的问题,对于自身遮挡关系比较复杂的对象,没有办法保证绘制的正确;无法进行检测,overdraw比较严重;再者对对象排序的操作,不适合硬件实现。

而另一种保证深度正确的算法就是ZBuffer算法,申请一块和FrameBuffer大小一样的缓冲区,如果开启了深度测试,那么在最终写入FrameBuffer之前(Early-Z实现类似,只是时机效果不同),就需要进行测试,比如ZTest LEqual的话,如果深度小于该值,那么通过深度测试,如果开启了深度写入,还需要顺便更新一下当前点的深度值,如果不通过,就不会写入FrameBuffer。ZBuffer保证像素级别的深度正确,并且实现简单,比起靠三角形排序这种不确定性的功能更加容易硬件化,所以目前的光栅化渲染中大部分都使用的是ZBuffer算法。ZBuffer算法也有坏处,第一就是需要一块和颜色缓冲区一样大小的Buffer,精度还要比较高,所以比较费内存,再者需要逐像素计算Z值,但是为了渲染的正确,也就是透视校正纹理映射,Z值的计算是不可避免的,所以总体来看,ZBuffer的优势还是比较明显的。关于ZBuffer的实现以及透视投影纹理映射,可以参照。

对于不透明物体来说,ZBuffer算法是非常好的,可以保证遮挡关系没有问题。但是透明物体的渲染,由于一般是不写深度的,所以经常会出现问题,对于透明物体,一般还是采用画家算法,即由远及近进行排序渲染。还有一种方案是关闭颜色写入,先渲染一遍Z深度,然后再渲染半透,就可以避免半透明对象内部也被显示出来的问题,可以参考之前的遮挡处理这篇文章中的做法。

透视投影的主要知识点在于三角形相似以及小孔呈像,透视投影实现的就是一种“近大远小”的效果,其实投影后的大小(x,y坐标)也刚好就和1/Z呈线性关系。看下面一张图:

上图是一个视锥体的截面图(只看x,z方向),P为空间中一点(x,y,z),那么它在近裁剪面处的投影坐标假设为P’(x',y',z’),理论上来说,呈像的面应该在眼睛后方才更符合真正的小孔呈像原理,但是那样会增加复杂度,没必要额外引入一个负号(此处有一个裁剪的注意要点,下文再说),只考虑三角形相似即可。即三角形EAP’相似于三角形EGP,我们可以得到两个等式:

由于投影面就是近裁剪面,那么近裁剪面是我们可以定义的,我们设其为N,远裁剪面为F,那么实际上最终的投影坐标就是:

投影后的Z坐标,实际上已经失去作用了,只用N表示就可以了,但是这个每个顶点都一样,每个顶点带一个的话简直是暴殄天物,浪费了一个珍贵的维度,所以这个Z会被存储一个用于后续深度测试,透视校正纹理映射的变换后的Z值。

但是还有一个问题,这里我们得到是只是顶点的Z值,也就是我们在vertex shader中计算的结果,只有顶点,但是实际上,我们在屏幕上会看到无数的像素,换句话说,这些顶点的信息都是离散的,但是最终显示在屏幕上的模型却是连续的,这个那么每个像素点的值是怎么得到的呢?其实就是插值。一个三角形光栅化到屏幕空间上时,我们仅有的就是在三角形三个顶点所包含的各种数据,其中顶点已经是被变换过的了(Unity中常用的MVP变换),在绘制三角形的过程中,根据屏幕空间位置对上述数据进行插值计算,来获得顶点之间对应屏幕上像素点上的颜色或其他数据信息。

这个Z值,还是比较有说道的。在透视投影变换之前,我们的Z实际上是相机空间的Z值,直接把这个Z存下来也无可厚非,但是后续计算会比较麻烦,毕竟没有一个统一的标准。既然我们有了远近裁剪面,有了Z值的上下限,我们就可以把这个Z值映射到[0,1]区间,即当在近裁剪面时,Z值为0,远裁剪面时,Z值为1(暂时不考虑reverse-z的情况)。

首先,能想到的最简单的映射方法就是depth = (Z(eye) - N)/ F - N。直接线性映射到(0,1)区间,但是这种方案是不正确的,看下面一张图:

右侧的三角形,在AB近裁剪面投影的大小一致,而实际上C1F1和F1E1相差的距离甚远,换句话说,经过投影变换的透视除法后,我们在屏幕空间插值的数据(根据屏幕空间距离插值),并不能保证其对应点在投影前的空间是线性变换的。关于透视投影和光栅化,可以参照上一篇文章中的内容。

透视投影变换之后,在屏幕空间进行插值的数据,与Z值不成正比,而是与1/Z成正比。所以,我们需要一个表达式,可以使Z = N时,depth = 0,Z = F时,depth = 1,并且需要有一个z作为分母,可以写成(az + b)/z,带入上述两个条件:

通过透视投影,在屏幕空间X,Y值都除以了Z(视空间深度),当一个值的Z趋近于无穷远时,那么X,Y值就趋近于0了,也就是类似近大远小的效果了。而对于深度值的映射,从上面看也是除以了Z的,这个现象其实也比较好理解,比如一个人在离相机200米的地方前进了1米,我们基本看不出来距离的变化,但是如果在相机面前2米处前进了1米,那么这个距离变化是非常明显的,这也是近大远小的一种体现。

Unity中生成深度图

先来考古一下,我找到了一个上古时代的Unity版本,/puppet_master //计算相机在远裁剪面处的xyz三方向向量 //构建四个角的方向向量

效果(开了Bloom后处理,有了Bloom,再挫的画面也能加不少分,哈哈哈):

本篇主要是总结了一下实时渲染当中关于深度(图)相关的一些内容,主要是透视投影,ZBuffer算法,1/Z问题,深度图的基本使用,Linear01Depth,LinearEyeDepth,ZBuffer精度,Reverse-Z,根据深度重建世界坐标等内容。另外,实现了软粒子,屏幕空间扫描波,扩散波,屏幕空间高度雾,运动模糊等常见的使用深度图的效果。效果的实现其实都比较基本,但是扩展性比较强,用深度可以做很多很多好玩的东西。文中的一些特殊效果实现已经给出了参考链接,另外还参考了乐乐大佬的《shader lab入门精要》关于运动模糊以及高度雾效的部分。不过我还是低估了深度的内容,精简过后还是这么多,可见,深度对于渲染的重要性。更加复杂的渲染效果,如SSAO,阴影,基于深度和法线的描边效果之类的,还是等之后在写啦。

注:文中的shader目前都没有考虑#if UNITY_UV_STARTS_AT_TOP的情况,在5.5版本以前(我只有4.3,5.3,5.5,2017,2018这几个版本,具体哪个版本开始不需要考虑这个问题,不太确定),PC平台,开启AA的情况下会出现RT采样翻转的情况。以前的一些blog是都加了这个宏判断的,不过目前测试的新版本2017.3貌似木有了这个问题(也可能触发条件变了),所以我就愉快地偷了个懒喽。

我要回帖

更多关于 unity hold on 卡住了 的文章

 

随机推荐