从基础算法到复杂图形:渲染器进阶与高能拓展
2024-01-12 21:33:48
十天自制软渲染器之三角形绘制(向量叉乘算法与重心坐标算法)
现在,我们在画完点和线后,终于可以来绘制三角形了。三角形可以算得上是最为简单,但同时也是最为强大的面了。本篇文章主要讲解三角形绘制算法的推导和思路,最后会给出代码实现,所以请耐心阅读下去。
在正式开始本章节前,我们先想想如何利用上一章节的画线算法来绘制一个实心的三角形。假设我们现在有一个平面内任意三角形,我们完全可以将三角形分解为多个小的三角形,然后用画线算法将其连接起来,从而实现三角形的绘制。如下图所示:
[图片]
为了实现这一效果,我们需要将三角形划分为尽可能多的子三角形,每个三角形的边长越短越好。这样,我们就能得到一个非常接近于实心三角形的图形。
一、三角形基础算法
接下来,我们详细看看绘制三角形需要用到的几个基本算法。
1. 向量叉乘算法
向量叉乘算法是一种计算两个向量的叉积的算法。叉积是一个向量,垂直于两个原始向量,其大小等于两个原始向量所张成的平行四边形的面积。
向量叉乘算法的公式为:
a × b = (a₂b₃ - a₃b₂, a₃b₁ - a₁b₃, a₁b₂ - a₂b₁)
其中,a 和 b 是两个向量,×表示叉乘运算。
2. 重心坐标算法
重心坐标算法是一种计算三角形中任意一点到三个顶点的相对位置的算法。重心坐标是一个三元组,其中每个元素表示该点到三个顶点之一的距离与三角形边长的比值。
重心坐标算法的公式为:
λ₁ = (x - x₃)(y₂ - y₁) - (x₂ - x₁)(y - y₁)
λ₂ = (x - x₁)(y₃ - y₂) - (x₃ - x₂)(y - y₂)
λ₃ = 1 - λ₁ - λ₂
其中,(x₁, y₁)、(x₂, y₂)和(x₃, y₃)是三角形的三个顶点坐标,(x, y)是三角形中任意一点的坐标,λ₁, λ₂和λ₃是该点的重心坐标。
二、三角形绘制算法的推导
现在,我们可以利用向量叉乘算法和重心坐标算法来推导出三角形绘制算法。
1. 首先,我们需要计算三角形的法向量
法向量是一个垂直于三角形平面的向量。我们可以使用向量叉乘算法来计算法向量。
n = a × b
其中,a 和 b 是三角形的两条边。
2. 接下来,我们需要计算三角形的重心
重心是一个三角形三个顶点的平均位置。我们可以使用重心坐标算法来计算重心。
G = (x₁λ₁ + x₂λ₂ + x₃λ₃, y₁λ₁ + y₂λ₂ + y₃λ₃)
其中,(x₁, y₁)、(x₂, y₂)和(x₃, y₃)是三角形的三个顶点坐标,λ₁, λ₂和λ₃是三角形中任意一点的重心坐标。
3. 然后,我们需要计算三角形的光栅化边界
光栅化边界是指三角形在屏幕上的投影的边界。我们可以使用重心坐标算法来计算光栅化边界。
for each pixel in the screen
λ₁ = (x - x₃)(y₂ - y₁) - (x₂ - x₁)(y - y₁)
λ₂ = (x - x₁)(y₃ - y₂) - (x₃ - x₂)(y - y₂)
λ₃ = 1 - λ₁ - λ₂
if λ₁ >= 0 && λ₂ >= 0 && λ₃ >= 0
draw pixel
其中,(x, y)是屏幕上像素的坐标。
4. 最后,我们需要填充三角形内部
我们可以使用光栅化算法来填充三角形内部。光栅化算法是一种将三角形分解为许多小的像素并填充这些像素颜色的算法。
for each pixel inside the triangle
draw pixel
三、代码实现
现在,我们已经推导出三角形绘制算法,我们可以用代码来实现它。
void drawTriangle(Triangle triangle) {
// 计算三角形法向量
Vector3 n = triangle.a × triangle.b;
// 计算三角形重心
Vector3 G = (triangle.a + triangle.b + triangle.c) / 3;
// 计算三角形的光栅化边界
for (int x = 0; x < screen.width; x++) {
for (int y = 0; y < screen.height; y++) {
Vector3 P = new Vector3(x, y, 0);
float λ₁ = (x - triangle.c.x)(triangle.b.y - triangle.a.y) - (triangle.b.x - triangle.a.x)(y - triangle.a.y);
float λ₂ = (x - triangle.a.x)(triangle.c.y - triangle.b.y) - (triangle.c.x - triangle.b.x)(y - triangle.b.y);
float λ₃ = 1 - λ₁ - λ₂;
if (λ₁ >= 0 && λ₂ >= 0 && λ₃ >= 0) {
screen.setPixel(x, y, triangle.color);
}
}
}
// 填充三角形内部
for (int x = triangle.xmin; x <= triangle.xmax; x++) {
for (int y = triangle.ymin; y <= triangle.ymax; y++) {
screen.setPixel(x, y, triangle.color);
}
}
}
四、示例项目
现在,我们已经用 C++ 实现了一个软渲染器,我们可以用它来绘制一些简单的三角形。
[图片]
五、后续发展
这个示例项目只是一个简单的开始,我们可以继续扩展它来实现更复杂的功能。例如,我们可以添加纹理、光照和阴影,甚至可以实现简单的动画。
总之,构建一个软渲染器是一个非常有趣和具有挑战性的项目,它可以帮助我们更好地理解计算机图形学的基本原理。