大家好,又见面了,我是你们的朋友全栈君。
定义一个宽高比(Aspect Ratio);还有垂直可视角度 vertical field-of-view (fovY) 。垂直可视角度即从相机原点到上顶中点和下底中点的连线的夹角,可视角度大可以类比成广角相机,它张得就比较开,适合拍近距离的物体;可视角度小,透视投影就越不明显,越像正交投影,就很容易能拍到远处的物体。水平可视角度可以类比。
这就是说,如果我们想要定义一个视锥的话,定义一个垂直可视角度、定义一个宽高比,其他的变量就都可以转化得到。
MVP 变换将三维物体投影到二维平面,所有物体都在 [ -1, 1 ]3 的空间里。那么下一步就是如何将这 [ -1, 1 ]3 的立方体在屏幕中显示出来,这就是光栅化。
屏幕就是一个典型的光栅成像设备。
我们定义屏幕左下角是原点,向右是 x,向上是 y。所有像素点的位置从 ( 0, 0 ) 到 ( width – 1, height – 1 ) 。像素 ( x, y ) 的中心在 ( x + 0.5, y + 0.5 ) 。屏幕的范围从 ( 0, 0 ) 到 ( width, height ) 。
我们首先不管 z 方向,只管 x、y 方向,即 [ -1, 1 ]2 转化到 [ 0, width ] × [ 0, height ] 。
就做了一遍缩放和平移。这种变换就叫做视口变换,将 [ -1, 1 ]2 的空间转化到 [ 0, width ] × [ 0, height ] 的屏幕空间。
那么接下来就是要真正把多边形打散成像素,即光栅化过程。
使用三角形作为基础形状几何体有众多好处。三角形是最基础的多边形,再退化就变成线段了;任何其它的多边形都可以拆分成三角形;三角形内部一定是平面的,比如四边形就不能保证是平面;三角形内外是清晰的,比如多边形内部如果有洞怎么办,像甜甜圈那样,如果不是凸多边形怎么办,其他多边形就有各种各样的问题,而三角形就可通过向量的叉乘来判断一个点是否在内部还是外部;只要定义三角形三个顶点的属性,在三角形内部就可做一个渐变来填充三角形内部所有像素的属性。
三角形覆盖的每一个像素点该如何取值呢?
这就是我们下一步要做的,光栅化中最重要的,即判断一个像素的中心点与三角形的位置关系。
有一个最简单的办法来做光栅化,就是通过采样(Sampling)的方法。采样其实就是对一个函数离散化的过程,比如 f(x) = sin x ,就要拿各种各样的点来问函数的值是多少。
那么我们拿像素中心来对屏幕空间进行采样,就是要算出屏幕空间的函数在某一个像素中心它的值是多少。
我们定义一个 inside 函数:
向量做叉乘,判断是否都在向量的左侧,则在三角形内部,否则就在外部。
考虑一个三角形,按特定顺序排列顶点 A、B、C,然后不断做向量叉乘,要么 z 全是正的,要么 z 全是负的,在这两种情况下才会判定像素点在三角形内部。
而如果一个点正好在三角形的边上,那就是自己定义了,可以不做处理,也可以特殊处理。
而且也不需要遍历所有的像素点,我们知道三角形三个顶点坐标后,就能确定一个最大的正方形区域,那是我们需要考虑的,其他的都不用处理。
光栅化也有其它的加速方法:
每一行我都找它的最左和最右,这样的话我一个像素也不会多考虑。对于某些细长条的斜向的三角形就很适合用这种方法。
真实情况下的光栅化:
第二种是 Bayer Pattern,可以让红绿蓝均匀地分布在屏幕空间上,可以看到绿色的点要更多,这是因为人眼本身对绿色最为敏感,比如在相机上也是这样,对绿色的感光元件会设置更多,从而人眼看上去要更舒服。
在彩色打印机上会有更复杂的分布:
光栅化后能看到一个很明显的现象,就是锯齿(Jaggies)
锯齿就是光栅化图形学里面一直在致力于解决的严重问题。
可以初步分析,我们的采样率对于信号来说是不够高的,所以产生了信号的走样问题(Aliasing)。所以我们下一步就是抗锯齿,或者反走样,这是图形学中重大的技术。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/155421.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...