3D 软件渲染引擎 - 第一部分
本文是关于 3D 软件渲染引擎的。
引言
本文介绍的是 3D 软件渲染引擎。我不会在这里讨论 DirectX 或 OpenGL。运行示例在纯 Windows GDI 中完成。
背景
您可以在 Code Project 上找到许多关于此主题的文章,请随意浏览。游戏编程领域非常广泛,涵盖了许多不同的技术技能,而不仅仅是某种编程语言的编程。我将尽量使本文篇幅简短,重点关注主要内容,因此这里不涉及其他内容,例如声音、音乐、物理、游戏 UI、游戏脚本等。
为什么是软件 3D 游戏引擎?
我想读到这篇文章的每个人都会问这个问题。好吧,编写游戏是编程的有趣部分。我们(程序员)在编写不同类型的应用程序时,总是问自己(或者更常问别人)是否有能力编写游戏。虽然由精灵组成的 2D 游戏可以在短时间内完成,但完整的 3D 游戏引擎并非易事。它需要时间、时间和时间才能完成。如果你 ever 完成它。好吧,我很难认为单个开发人员能够处理商业质量 3D 游戏引擎的所有主要子系统,而是专注于他最了解的部分。所以,除了需要时间之外,还需要一个团队。它还需要扎实的数学和物理知识。
那么,人们会问,为什么不使用现成的引擎,而是从头开始编写自己的引擎?这与此相同,或者几乎相同。但是,通过编写自己的游戏引擎,您可以学习并快速练习编码,对吧?
您还需要一本好书来开始学习游戏引擎。我将再次推荐 Andre Lamothe 的技术书籍(《3D 游戏编程大师的秘诀》)。这位作者有一整套专门介绍此主题的书籍。它可能不是现代游戏编程的最新技术,但对于游戏编程的初学者和中级开发人员来说,它足以作为基本来源。这是一个很好的阅读和学习的起点。
我将在本文中尝试转移我从阅读这本书中获得的经验。
3D 世界 - 多边形
所有 3D 图形都由称为三角形的简单多边形构成。所有现代图形卡都只处理这些简单的多边形。

请看上图的示例。这个简单的立方体由 12 个三角形组成。这个 3D 模型恰好有 8 个顶点和 12 个定义的(三角形)多边形。因此,要渲染 3D 立方体,您必须渲染它组成的多边形,所以我们基本上只处理三角形。如果你知道如何绘制一个三角形,你就能渲染任何形状的 3D 对象,即使是最复杂的。
线框渲染
我们将涵盖的第一部分是线框绘制。这是一种简单的渲染技术,您只绘制三角形的边,而不填充颜色。每个三角形需要绘制三条线连接相应的三个顶点。我们需要一些好的(或任何可用的)线绘制算法,例如 Bresenham 算法。您可以在 此处找到它,并附有所有解释。您可以在下图看到该算法的工作原理。

所以,基本上您计算线的斜率并从起点插值到终点。斜率由下式给出:
Slope = dy / dx = m = (y1 - y0) / (x1 - x0)
您可以在下一张图中看到,当演示应用程序以线框模式运行时,它的外观如何。

我们的 3D 模型现在完全可见了。然而,您可能会问,那些不可见的立方体侧面(背面)发生了什么?它们没有在此场景中渲染,以避免给观看者带来过多细节,尽管在线框模式下通常也会显示它们。
纯色渲染
所有 3D 对象都具有一定的体积。在线框模式下,我们可能无法清楚地看到它。然后我们需要用某种颜色填充这些三角形。现在,假设所有三角形都具有相同的颜色。那么,如何填充三角形?这并不比绘制它更难。只是,您应该将通用三角形转换为更容易处理的内容,而不是逐行绘制。请看下图。

您可以在此处看到通用三角形如何被分解为两个简单的三角形,这些三角形更容易使用基本扫描线栅格化器进行栅格化。有关此扫描线栅格化器实现,请参见下图。

扫描线栅格化器计算从顶顶点(如果我们处理的是底部平坦的三角形)出来的两条线的两个斜率。与绘制线类似,这里我们从上到下,只需用指定的颜色填充内部像素。所以,我们不像以前那样只绘制两条线的两个像素,而是绘制这两条边缘像素之间的所有中间像素。对于顶部平坦的三角形,情况相同,只是我们是从底部顶点到三角形的顶部。
现在您可以看到演示应用程序以纯色模式运行的屏幕截图。

现在立方体看起来更有趣了,对吧?它应该在 3D 世界中占据一定的空间。
平面着色
现在是时候谈谈光了。现实世界中有光,所以 3D 世界也应该有光。由于光线数学可能相当复杂,我不会深入探讨,而是向您展示一些基本的照明模型算法以及它如何反映到我们的纯色渲染中。
有几种类型的光源:
- 环境光
- 定向光
- 点光源
- 聚光灯
所谓的平面着色考虑了表面(三角形)法线,并平均了不同光源对相应表面(三角形)的影响。请看下图。

演示应用程序以平面着色模式运行的屏幕截图显示在下一张图中。

现在我们的立方体看起来更逼真了。所以,之前的三角形栅格化算法在这里没有改变,它只是考虑了每个表面(三角形)的不同颜色。
Gouraud 着色
这种着色类型为我们的 3D 世界带来了更多真实感。它是一种渐变类型的着色。为此,需要每个顶点的法线,而不仅仅是表面(三角形)的法线。

下面显示了使用 Gouraud 着色进行三角形栅格化的算法。

因此,在绘制三角形时,颜色会在顶点之间进行插值。下图显示了演示应用程序以 Gouraud 着色模式运行的屏幕截图。

由于光滑的渐变显示了立方体表面如何响应光照,因此这个 3D 立方体现在看起来更好了。
纹理
3D 对象需要具有某种材质或纹理,才能增强它们所代表的真实感。这就是图像(纹理)发挥作用的地方。但是,如何将它们应用到表面(三角形)上?
这里我们说有两种类型的纹理映射:仿射和透视。下图显示了它们的区别。

下一张图显示了纹理映射的设置。

所以,这里的关键是将图像(纹理)中的区域转移到表面(三角形)上。由于我们已经在 Gouraud 着色部分涵盖了颜色插值,因此此处也使用了相同的方法。我们在此处插值的是图像坐标,而不是颜色。
下图显示了演示应用程序在纹理映射模式(未应用任何着色)下运行的屏幕截图。

现在,这看起来非常漂亮和真实,不是吗?
平面着色纹理映射
这是光照和应用纹理的简单组合。在插值过程中,当您对三角形进行栅格化时,您会混合表面的最终颜色(三角形)和应用的纹理。将表面(三角形)的默认颜色设置为纯白色并应用光照很容易,然后将生成的像素值与纹理中的像素组合起来。您在计算光照后获得的灯光贴图会混合到纹理中。请看下图。

这已经足够真实了。
Gouraud 着色纹理映射
这里我们使用 Gouraud 着色而不是平面着色,并将其与应用的纹理混合。请看下图。

现在,这对我来说足够好了。你觉得呢?
我到目前为止告诉您了什么
此时,您肯定已经理解了如何使用自己的软件渲染器以不同的模式渲染 3D 模型。但是,这仅仅是我设计的 3D 软件渲染器的文章系列的第一个部分。就本文而言,您可以自由尝试构建自己的光栅化器。在下一部分中,我将向您展示每个 3D 游戏引擎的基础:3D 模型、投影、摄像机系统、纹理过滤、游戏物理等。
下一篇文章还将介绍可以进行的优化,以便软件渲染器不必像最初假定的那样慢。
关注点
我非常喜欢图形编程,我也喜欢玩游戏。这是我构建 3D 游戏引擎图形子系统的尝试,并向读者解释了可用的简单技术,他们可以用来构建它。
历史
3D 软件渲染器 v1.0 于 2011 年 3 月 17 日发布。