《C++从零打造渲染器》学习笔记 第0讲:图形学导论
第0讲:图形学导论
说明:本教程基于B站图形学大佬 发财学长 制作的 C++从零打造渲染器 系列视频。写这篇文章的目的主要是作个人学习笔记,如果这份笔记能帮到他人,本人不胜荣幸
[视频链接:【C++从零打造渲染器】第0讲:图形学导论(别再只调API了,我们从零写一个真正的渲染器!)
什么是图形学
狭义的图形学:渲染
广义的图形学:动画,物理……
什么是渲染
渲染,就是计算屏幕每个像素的颜色,即(R,G,B)值
Color screen_pixels[W][H];
for(int x = 0;x < W;x++)
{
for(int y = 0;y < H;y++)
{
screen_pixels[x][y] = RenderPixel(x,y);
}
}
Present(screen_pixelss);
图形学的核心问题,就是实现RenderPixel函数
Color RenderPixel(int x,int y)
{
Color color = ......;
// ......
return color;
}
实现这个函数,需要有一个能够表示想在屏幕中绘制的内容
我们将它称为:数据集(Data)
举例:实现一个生成左上角(100,150),右下角(300,400),红色矩形的RenderPixel函数
Color RenderPixel(int x,int y)
{
if(x >= 100 && x <= 300 && y >= 150 && y <= 400)
return Color(255,0,0);
else
return Color(0,0,0);
}
效果如下:

举例:实现下面数据集对应的RenderPixel函数
Data =
{
矩形A:{红色,左上角(100,150),右下角(300,400)};
三角形B:{黄色,P1(30,120),P2(100,200),P3...};
圆形C:{紫色,O(350,450),R = 50};
}
Color RenderPixel(int x,int y)
{
if(在A中)
return Color(255,0,0);
else if(在B中)
return Color(255,255,0);
else if(在C中)
return Color(115,45,245);
else
return Color(0,0,0);
}
效果如下:

注意:if-else的判断顺序决定了图形的覆盖关系
我们将这个判断顺序,叫作图形的深度
总结: 渲染就包含两件事
-
数据集怎么定义,怎么组织
-
RenderPixel函数怎么实现
拓展到3D渲染器
当数据集允许包含三维图形时,这时候我们要写出RenderPixel函数,就要建立出 2D的屏幕 和 3D的数据集 之间的转换关系
实现这种转换关系的算法,叫作光线追踪

光线追踪
-
假设屏幕前面有一个相机
-
从相机出发,往屏幕上每个像素引出射线
-
求射线和数据集中哪个物体相交
举例:实现下面数据集对应的RenderPixel函数
Data =
{
球:{红色,球心O(30,100,-40),半径 R = 50};
}
Color RenderPixel(int x,int y)
{
Ray ray = GetRay(x,y);
if(ray和球相交)
return Color(255,0,0);
else
return Color(0,0,0);
}
效果如下:

另一种渲染器架构
渲染 和 绘制 的区别:渲染是按照像素点生成图像的,这种生成图像的方式不符合现实中画家作画的思路
有一种渲染器架构,主要思想是模拟现实作画的思路,叫作光栅化算法
Color screen_pixels[W][H];
for(shape : data)
{
Point pixel_coords[] = Rasterize(shape);
for(Point p : pixel_coords)
screen_pixels[p.x][p.y] = shape.color;
}
Present(screen_pixelss);
计算“某个Shape占据屏幕中的哪些像素点”的函数,叫作光栅化(Rasterize)
对比两种渲染器
光线追踪渲染器:一般用于离线渲染,特点是渲染慢,效果好
光栅渲染器:一般用于实时渲染,特点是渲染快,效果有牺牲
现代渲染器为了实现性能高,画质好,往往结合了两种渲染器

浙公网安备 33010602011771号