0%

27:初始图形学(1)

最近对图形学比较感兴趣,虽然感觉找不到工作,但是帅,我花点时间学一下,刚好练习一下C++

输出一个图像

ppm

当我们启动一个渲染器时,我们需要一种方式来查看我们的图像。最简单的方式就是将它写入文件中,这里我们使用PPM格式(因为它比较简单)

image.png

这是PPM文件格式在维基中的表现:

  • 第一行是文件描述子 什么P1 P2 P3代表了不同的图像类型,这里我们使用P3——像素图
  • 第二行是像素的宽高 先宽后高
  • 第三行表示每个像素分量的最大值 255 即8位色彩深度
  • 下面是像素的信息,每一行的最后用换行符结尾

图形学的Hello World

我们可以用简单的代码实现一个这样的图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
int main(){
int image_width = 256;
int image_height = 256;

std::cout << "P3\n" << image_width << " " << image_width << "\n255\n";

for (int j =0 ;j<image_height;j++){
for(int i=0;i<image_width;i++){
auto r = double (i)/(image_width-1);
auto g = double (j)/(image_height -1);
auto b = 0.0;

int ir = int (255.999 *r);
int ig = int (255.999 *g);
int ib = int (255.999 *b);
// 255.999确保在浮点数计算中的极小误差在转换为整数的过程中不会被放大,可以理解成这是一种技巧,用来避免色彩的丢失
std::cout << ir << ' ' << ig << ' ' << ib << '\n';
}
}
}

我们将输入定向到一个文件中,然后更改后缀名打开

image.png

可以看到我们生成的图片啦

添加一个程序进度指示器

有时候长时间渲染需要进行跟踪,以判断是否陷入死循环中,或者查看渲染进度。

我们可以通过添加日志输出流来实现这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
int main(){
int image_width = 256;
int image_height = 256;

std::cout << "P3\n" << image_width << " " << image_width << "\n255\n";

for (int j =0 ;j<image_height;j++){
std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
for(int i=0;i<image_width;i++){
auto r = double (i)/(image_width-1);
auto g = double (j)/(image_height -1);
auto b = 0.0;

int ir = int (255.999 *r);
int ig = int (255.999 *g);
int ib = int (255.999 *b);

std::cout << ir << ' ' << ig << ' ' << ib << '\n';
}
}
std::clog << "\rDone \n";
}

这样就可以啦