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

光栅化 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 设计