unity如何实现图片透视_非常规透视矩阵视锥直观理解与运用

最近和透视矩阵打的交道比较多,对于如何理解该矩阵有了足够直观的认识。去折腾透视矩阵的理由多半是和透视矫正相关,这多少会去与透视矩阵接触。(这里指的透视矫正并非图形学中插值的矫正,而是指更广义的,一切收到透视关系影响的矫正,例如移焦效果、特定物体透视减弱) 此文的主旨表达了本人对矩阵的直观感想以及几个透视矫正trick的实现,个人理解还处于初学者的浅显阶段,抛砖引玉希望能帮到其他新手。 文章内容先内容从前到后为:Pure Perspective Projection、最常见的透视矩阵理解,斜视锥透视矩阵实现的移焦效果理解、二次元卡通人物透视矫正trick在unity的实现。本文的坐标系全部基于Unity。

为什么要使用矩阵来进行透视转换

从最原始的状态思考,透视矩阵干了这么一件事:将远处的物体映射到近处,直到视野范围看到的所有物体都在一个平面上。

d4d9112f6e95ac23f5081d21e89ba5dd.png

从右视图上看视锥体,我们先假设近平面离原点距离Near=1,那么不管远处的物体其y值为多少,映射到近平面上显然就等于|y/z|,直线y=k(-z)上的所有点都将汇聚成近平面上的一个点。这对于顶视图的xz而言也是一样的。

所以要进行透视映射,最想要知道的xy映射后的关系我们已经知道了,xy除以z得到值为1的平面上的投影x’y’,如果近平面的值为N(Near),则x’=x*(N/z), y’=y*(N/z)。对于z值,保留初始值就好了,考虑到充分利用上远平面参数,如果能再算出一个0-1范围的z值对应于进远平面存起来就更好了,这会是我们最初的想法。

为什么前人计算这么一个透视关系就能直接想到4x4矩阵上去,是我一直疑惑的点。对于矩阵功底不深的我而言,直接使用上述表达式才是最容易理解的,于是我查了查齐次坐标提出的年份:1827年,对比再1950年才开始发展的计算机图形学,早了一百多年。对于我们这个时代的人而言,可能很多人线代都没怎么学就去学投影矩阵了,然而那时候图形学发展初期,我只能认为是大佬们已经有了深厚的数学基础,毕竟齐次坐标系的引入投影可以进行形状变化,是数学圈这一百年中早已玩烂的东西,人与人的体质不可一概而论。

啰嗦了这一大段,其实就是为了树立4x4矩阵可以进行透视变化的信心,故下文开始就要讲我是如何直观理解透视矩阵的,不需要推导,直接便可以将矩阵写出来。

我们的需求是:将view space下坐标点为(x,y,z, 1)的点,转化到(x' =x/ x/z, y’ = y/z, z’= some value range of(0,1) remap from (near, far), w=z),其矩阵即为下面的Pure Perspective Projection:

19666ed89c8b3db3f7384b65419d893e.png

基础矩阵直观理解这里不赘述,推荐看3Blue1Brown的相关视频。这里矩阵乘法得到的(x’=x, y’=y, z’=z, w’=z),齐次除法时, xy映射到x’= x'/w'= x/z, y’= y'/w' = y/z,是我们期待的结果,不过z’=z/z=1是个常量,不是我们想要的从0到1的深度比例值, 在这里不妨碍我们理解, 整个矩阵的精华是第四行的第三列为1。

下面来看看网上最常见的透视矩阵书写形式:

13756a8294aa771b27a22613c25cbb18.png

其实这么写反而妨碍了我们的直观理解,由Aspect、Fov与w(width)、h(height)、N(Near)、F(Far)的关系,我们应当写成如下形式:

2d1eefdb9509fff3e59c9fdd8af62231.png

发现了吗,和透视矩阵之母Pure Perspective Projection的区别,第一列第一行的1变为了N*(2/w)这么一个缩放值。2/w很好理解,是将屏幕像素宽度缩放到长度为2,左半边为-1,右半边为1,而乘上N 考虑到结果的齐次除法xyz分量都要除以w分量,矩阵转化后的w分量等于转化前的z分量相反数, 故x'/w'= x/z, y'/w' = y/z,是我们要的投影到近平面为1的值,这个值乘上N就相当于映射到了近平面,即true x’ =(N/z)*(2/w)。 相应的,有mat[1][1]的1改为2N/h。

到此位置,我们能直接写出这样一个透视矩阵:

af2284d24776fe1efb402a929be91a75.png

Pure Perspective Projection中没有解决的z’映射0-1, 我们这里开始做一次:

49b5ec8e2e34ef35bc3688e5e3edb7ae.png
计算出a与b的值,填补矩阵即可得到常规透视矩阵

扩展到移焦效果的斜视锥体

先来讲讲什么是斜视锥体和移焦效果:

7f1f590ae8cf3a6d1e1dabf41ea733a4.png
AUTODESK文档

c81ea070d864b2fa0c99a6f840717b77.png

简言之,移焦效果程序实现上就是将远近平面进行平移,使之对称轴不再等于z轴,如果希望构图上将一个物体移动到另一处地方而不改变其透视关系,那么移焦便是我们需要的,反映到项目上,可以是在选角色界面,当想要一个相机拍出来的人物显示到屏幕左侧而非正中央时,希望其透视关系仍然与在正中央相同,则需要移焦。

6f566a95b66c911c905342f3b3b02824.png

在Unity之前的版本中,其实只需要更改相机的Viewport Rect即可,但是URP下Camera Stack的存在,只允许Base相机更改Viewport Rect,栈中的Overlay相机不开放此参数,引发了诸多惨剧:

494603a961b098c84ba92a6511694fe5.png
Yep same here! fucking shit unity !

不过天无绝人之路,移焦效果也可以通过开启Physical Camera后调整Lens Shift来实现,这是Unity自带已有的功能。

5e8370d89609d9315593d25148b80967.png

c6d1b53f1f311d54381de2aa45af8c60.png

实现效果:

2c2ead2caae2290a04dc473668fe410a.png

87cb99edd0472df19529efe6cd61ae01.png
cube看起来明明是在屏幕左边,却看不到其右边的面,透视保持和在中间时一样

当项目中用到了平面反射时,可能需要直接设置移焦透视矩阵,此时了解该矩阵如何写是必要的。

有了前面两矩阵的直观理解,我们知道达成移焦效果需要移动中心轴,简单说,即随着z绝对值的增大,xy均进行了偏移。

ecdff15f42a14477dbd2d978c5c46a11.png

因此我们需要重新改写透视矩阵,只需要让x与y在矩阵转化后与z成比例进行偏移,考虑到shift_x与shift_y为-0.5与0.5时,我们希望视锥体的右、左半边直接消失,我们可以直接得到下列矩阵

bf19b97ba52182fa04bff68e51bfe7d9.png

ac43f82d827e6bdc6e57bd13c0af1812.png

92cfb68ca6bbd5ab7947379f0da6101b.png
其中Sx=Shift_x, Sy=Shift_y

其他有趣的透视矫正trick

二次元人物一般来说会希望透视尽可能小,然后在特定时机又要有夸张的大透视,参考了b站up IOChair 的思路,我在shader中的view space里以物体的轴点为参照,压扁了其z值,思路很简单,上代码更快:

109cb7eb487cf9ed902e596909cbaee8.png

当脚本控制的_PerspectCor为1时,代表不进行透视矫正,当PerspectCor为更大的值的时候,此时表现出来的人物效果,将越发接近于正交效果,因为此时人物的厚度无线接近于0,虽然看起来像3d,实际上已经是纸片人了,下面是几个使用了该trick的视频结束本文233:

知乎视频​www.zhihu.com
知乎视频​www.zhihu.com
知乎视频​www.zhihu.com
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值