跳转至

2 Rasterization

文本统计:约 2030 个字 • 11 行代码

What’s after MVP(Model/View/Projection transformation)? We need to convert the Canonical Cube to Screen called Rasterize.

Define the screen space:

  • Pixels ’s indices are in the form of \((x,y)\)
  • Pixels ’s indices are from \((0,0)\) to \((\text{width}-1,\text{height}-1)\)
  • Pixel \((x,y)\) is centered at \((x+0.5,y+0.5)\)
  • The screen covers range \((0,0)\) to \((\text{width},\text{height})\)

Transform in \(xy\) plane :\([-1,1]^2\) to \([0,\text{width}]\times[0,height]\)

\[ M_{viewport}=\left(\begin{matrix}\frac{\text{width}}{2}&0&0&\frac{\text{width}}{2}\\0&\frac{\text{height}}{2}&0&\frac{\text{height}}{2}\\0&0&1&0\\0&0&0&1\end{matrix}\right) \]

2.1 Sampling

We use triangles as the fundamental shape primitives.

WHY?

  • Most basic polygon, other polygons can be broken to triangles
  • Guaranteed to be planar
  • Well-defined interior and easy to judge

Then we need to use set of pixel values to approximating triangle, one way to solve is sampling(采样). If the center of pixel is inside triangle, we sample this point.

\[ \text{inside}(t,x,y)=\begin{cases}1 ,&\text{Point (x,y) in triangle t}\\0 ,&\text{otherwise}\end{cases} \]
for (int x=0;x<xmax;++x)
    for (int y=0;y<ymax;++y)
        image[x][y] = inside(tri,x+0.5,y+0.5)

How do I know if \(O\) is in \(\triangle ABC\) ? Just calculate \(\overrightarrow {AO} \times \overrightarrow {AB}\) and \(\overrightarrow {BO} \times \overrightarrow {BC}\) and \(\overrightarrow {CO} \times \overrightarrow {CA}\)

  • if their sign all the same, \(O\) is in \(\triangle ABC\).

  • if there is 0, \(O\) is on the boundary of a triangle.

我们做光栅化的时候,是遍历了整个屏幕的所有点去采样的。所以我们只需要取一个Bounding Box (包围盒),在这个包围盒中处理采样(如下左图)

当然还有更快的方法,就是在每一行中取最小和最大(每一行构成一个包围盒),如上右图,这种方法在较瘦和有一定旋转角度的情况提升较大。

2.2 Anti-aliasing

Just use the way above has one problem: Jaggies(锯齿) 学名被称为 aliasing(走样),

Sampling artifacts are common in Computer Graphics, including Jaggies, Moire, Wagon Wheel effect...

The reason behind the Aliasing Artifacts is that Signals are changing too fast and sampled too slowly(信息变化过快但是采样速度较慢).

Anti-aliasing Idea: Blurring or Filter before sampling (NOT Sample then filter!)

Why undersampling introduces aliasing?

Higher frequencies need faster sampling, so undersampling creates frequency aliases.

Example

比如说两个频率不同的正弦函数,如果采样频率较低,那么这两种不同频率的正弦函数就无法被区分了,这就被称为走样。

Spatial domain and Frequency domain

By FFT, we can transform an image from spatial domain(时域) to frequency domain(频域).

Filtering means getting rid of certain frequency contents.

右边这个图越靠近中心频率越低,频率的意思是图像灰度值的梯度,图像变化越剧烈频率越高。

【高通滤波】将频率较低的部分过滤掉后,图像就只剩下变化剧烈的部分(边缘)

Convolution Theorem |卷积定理

卷积的意思就是一种平均的操作

一个一维的卷积操作

Convolution in spatial domain is equal to mutiplication in the frequency domain. 时域上的卷积等价于频域上的乘积

也就是说,我们要完成时域上的卷积,可以直接在时域上操作,也可以先转为频域,然后相乘后通过逆傅里叶变换得到时域的结果,如下图。

Sampling

什么是采样呢?就是重复原始信号的频谱 Sampling = repeating frequency contents

a是原始信号,c是冲激信号,e是ac的乘积;b和d分别是a和c经过傅里叶变换后得到的频域上的图像,由卷积定理,时域上的乘积等于频域上的卷积,f则是b和d卷积的结果,得到的就是频谱信号的重复。

所以当采样频率过低的时候,就会发生混叠。(如下图所示)

So, aliasing = mixed frequency contents

How can we reduce aliasing error?

Option 1 is increasing sampling rate (But we need to do anti-aliasing at the same sampling rate)

Option 2 is anti-aliasing :

Filtering out high frequencies before sampling.

将高频信号过滤掉,那么在较低的采样频率下也不会发生混叠

怎么做这样的模糊呢?可以直接选择一个1像素的box filter,对一个像素中的颜色求平均。

In rasterizing one triangle, the average value inside a pixel area of \(f(x,y) = \text{inside}(\text{triangle},x,y)\) is equal to the area of the pixel covered by the triangle.

那么在实际上,我们不可能把面积算出来之后接着得到相应的灰度值,我们可以使用超采样的方法(MSAA)

通过采样一个像素内的多个位置并平均它们的值来近似1像素盒滤波器的效果

MSAA的过程

我们得到的最后的采样结果

Warning

This method does not increase the sampling rate, but increases the number of sampling points. The cost of this method is increasing the calculation.

我们不是通过增加分辨率来解决走样问题的,而是增大采样点的数目来做到的。这样的结果就是计算量变得非常大

Anti-aliasing Today

FXAA (Fast Approximate AA) 先得到有锯齿的结果,然后再进行处理,具体来说就是通过图像处理的办法找到边界,然后将边界换成没有锯齿的边界,它与采样无关,是一种图像的处理技术

TAA (Temporal AA) 对于静态图像的处理,利用上一帧的图像

2.3 Visibility / Occlusion

Painter’s Algorithm: Paint from from back to front, overwrite in the frame buffer

先画远的物体,再画近的物体,这种方法看似是对的,但是如果互相遮挡的情况出现了一个环,那么这个算法就不起作用了,比如说下方这个图

进一步思考,我们是否可以仅仅对像素进行排序,而不对三角形进行排序?所以我们引入 Z-buffer

Note

For simplicity we suppose z is always positive (smaller z -> closer, larger z -> further) 尽管我们的相机是向-z方向的,我们这里定义的z为物体到相机的距离

Idea

  • Store current min. Z- value for each sample(pixel) 对每个像素存储最小的Z值
  • Needs an additional buffer for depth values: frame buffer stores color values, depth buffer stores depth. 同时存储一些颜色数据等等

每次渲染的时候都是同步生成下面这两张图(越黑越近,越白越远)

Algorithm

  1. Initialize depth buffer to \(\infty\)

  2. During rasterization:

for (each triangle T)
    for (each sample (x,y,z) in T)
        if (z < zbuffer[x,y]) // closest sample so far
            framebuffer[x,y] = rgb; // update color
            zbuffer[x,y] = z; // update depth
        else
            ; // do nothing, this sample is occluded

All objects operated on are pixels 所有的操作都是针对像素的

Complexity:

  • \(O(n)\) for \(n\) triangles (assuming constant coverage)
  • we do not sort the triangles, we just need to get the minimum depth

If different triangles do not have pixels on the same depth, the result is independent with the drawing orders.

2.4 Shadows

—— shadow mapping

An Image-space Algorithm (在生成阴影这一步不需要知道几何信息)

  • no knowledge of scene’s geometry during shadow computation
  • must deal with aliasing artifacts

Key idea: 不在阴影中的点必须同时被光线和相机看到 (只能处理点光源)

Shadow mapping 的相关步骤

从光源看向场景,计算每个点的深度

Depth image from light source

Standard image (with depth) from eye

Project visible points in eye view back to light source

左图说明这个点是可见的,因为从相机到这个点的深度与眼睛看到的点反射线对应到相机的深度相同,而右图相机在这条线上的深度比眼睛看到的点反射线对应到相机的深度要浅。

总的来说就是在虚拟相机的位置生成一张深度图,然后再眼睛的方向观察某个点测得其到摄像机的距离,然后找到深度图对应的深度,比较即得到阴影的位置。

但是因为关于浮点数的精度问题会导致阴影边缘并不清晰,我们可以改进为大于,或者大于并且大于某个稍大的值,但这些都不能解决本质问题。

Example

如何生成以下带阴影的图

从光源处生成深度图

比较眼睛看到的位置到光源的位置的距离与深度图

生成相应的带有阴影的图

这个方法只能做阴影,有着非常锐利的边缘

Hard shadows v.s. soft shadows

软阴影只有再光源有大小的时候才可能出现,阴影的亮度与看到的光源的大小有关。

评论区

对你有帮助的话请给我个赞和 star => GitHub stars
欢迎跟我探讨!!!