编写光栅化渲染器(一)概述

# 光栅化 VS 光线追踪

图形学研究如何使用计算机模拟现实,当我们在谈渲染的时候,大致可以分为两个方向:

  • Ray Tracing,即光线追踪,一般用于离线渲染,效果好,但是计算量大,耗时长。
  • Rasterization,即光栅化,一般用于实时渲染,效果差,但是计算量小,耗时短。

实际上,在现代 GPU 和各种光栅化渲染算法的的加持下,光栅化的效果已经非常逼真了,光栅化的效果一点也不差。只是相比于光线追踪来说,效果还是差点。

一个简单的光线追踪流程:发射一条光线,经过一系列地镜面反射、漫反射、折射等现象,最终打到一个物体上,得到一个颜色。几个原因导致了计算量的爆炸:

  1. 像素数量多
  2. 因为反射和折射结果不稳定,一个像素需要几十甚至上百次采样平均才能获得一个稳定的结果
  3. 每一次采样都会反射或者折射很多次
  4. 每一次反射或者折射,都需要和场景中的每个物体相交判断,不过使用屏幕空间划分技术可以解决这个问题

总结一下,光线追踪的时间复杂度:Pixel * Sampling * (Reflection + Refraction) * (Object + Light),堪称炸裂。

如果你使用了屏幕空间划分技术(例如 BVH),会让结果好很多:Pixel * Sampling * (Reflection + Refraction) * log(Object + Light)

还有一种优化思路,就是让采样结果更加稳定,一旦采样结果稳定了,就可以大幅减少采样数量,在传统的 Whitted Style Ray Tracing 中,具体的措施有比如通过蒙特卡洛方法求各种表面和光源的概率分布,比如对光源进行重要性采样。

一个简单的光栅化流程:把场景中所有物体的点经过矩阵计算映射到 2D 屏幕空间,三个顶点构成一个三角形,对每一个像素,取最近的三角形,计算三角形在这个像素的颜色(通过三个顶点颜色插值)。

# 像素

无论是哪一种,都需要靠屏幕来展示它们,屏幕由一个一个像素构成,那么什么是像素呢?

通常来说,大部分普通人眼里的像素是这样的:

Rasterization

这种网格模型深入人心,但是这种模型仅仅在光栅化的时候才是可接受的,对于光线追踪来说,可能完全不是这样。

像素并不是你想得那么简单,更加专业的图形学人会告诉你:像素是一组离散的对场景颜色的采样结果,之所以这么说,是因为像素可能是一个采样点,也可能是多个采样点混合而成的,它的采样区域可能是方形的,也可能是圆形的。

所以,网格像素模型只是一种光栅化的时候简化像素的处理:我们认为在这个网格区域内,只产生一次采样,它处于网格的正中心。

那么如果要渲染一个场景,只需要把每一个网格填上颜色就可以了,光栅化实际上就是在聊怎么填颜色这件事情。比如你需要对场景里的物体进行排序,离相机近的物体表面颜色就是你想要绘制的图形的颜色。

光线追踪技术则是基于物理,从一个像素点出发,经过多次反射,得到最终颜色,但是一个像素一条射线远远不够,因为这样误差会很大,往往一个像素需要数百条射线的结果求平均。

光线追踪的本质就是对场景不断进行采样以降低噪点,最终得到最接近真实的图像。

从时间复杂度来说,光栅化无疑比光线追踪来得更加好,但是因为缺少严谨的物理模型,光栅化的效果比光线追踪差很多,所以在对性能要求不高,但是对效果要求高的离线渲染中,光线追踪被普遍运用。

截至文章编写日期,已经有游戏比如 赛博朋克2077 2.0 运用了 Path Tracing 技术,也叫 Monte Calo Ray Tracing,比传统的 Whitted Style Ray Tracing 性能更加好,效果也更棒。

# 光栅化程序开发流程

  1. 创建一个窗口,并绘制直线,三角形,带有顶点数据的物体。

施工中…

# Reference

Fundamentals of Computer Graphics

使用 Hugo 构建
主题 StackJimmy 设计