0%

【RayTracer】(八)构建随机场景

到目前为止,最简单的光线追踪器就构建完成了,在开始进一步完善之前,我们先随机向场景中加入许多不同材质不同属性的球体,渲染第一张“完整的”光线追踪图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <iostream>
#include <string>
#include <omp.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include "hittable_list.h"
#include "sphere.h"
#include "color.h"
#include "camera.h"

// 随机构建场景
hittable_list random_scene() {
hittable_list world;

auto ground_material = make_shared<lambertian>(color(0.5, 0.5, 0.5));
world.add(make_shared<sphere>(point3(0, -1000, 0), 1000, ground_material));

for (int a = -11; a < 11; a++) {
for (int b = -11; b < 11; b++) {
auto choose_mat = random_double();
point3 center(a + 0.9 * random_double(), 0.2, b + 0.9 * random_double());

if ((center - point3(4, 0.2, 0)).length() > 0.9) {
shared_ptr<material> sphere_material;

if (choose_mat < 0.75) {
// diffuse
auto albedo = random_vec() * random_vec();
sphere_material = make_shared<lambertian>(albedo);
world.add(make_shared<sphere>(center, 0.2, sphere_material));
}
else if (choose_mat < 0.95) {
// metal
auto albedo = random_vec(0.5, 1);
auto fuzz = random_double(0, 0.5);
sphere_material = make_shared<metal>(albedo, fuzz);
world.add(make_shared<sphere>(center, 0.2, sphere_material));
}
else {
// glass
sphere_material = make_shared<dielectric>(1.5);
world.add(make_shared<sphere>(center, 0.2, sphere_material));
}
}
}
}

auto material1 = make_shared<dielectric>(1.5);
world.add(make_shared<sphere>(point3(0, 1, 0), 1.0, material1));

auto material2 = make_shared<lambertian>(color(0.4, 0.2, 0.1));
world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2));

auto material3 = make_shared<metal>(color(0.7, 0.6, 0.5), 0.0);
world.add(make_shared<sphere>(point3(4, 1, 0), 1.0, material3));

return world;
}


int main()
{
/****图片保存,保存为png格式****/
std::string SavePath = "D:\\TechStack\\ComputerGraphics\\Ray Tracing in One Weekend Series\\Results\\";
std::string filename = "final.png";
std::string filepath = SavePath + filename;

/*******图片属性*******/
// 宽高比
const auto aspect_ratio = 3.0 / 2.0;
const int image_width = 1200;
// 使用static_cast可以明确告诉编译器,这种损失精度的转换是在知情的情况下进行的
// 也可以让阅读程序的其他程序员明确你转换的目的而不是由于疏忽
const int image_height = static_cast<int>(image_width / aspect_ratio);
const int channel = 3;
// 每个像素的采样数量
const int samples_per_pixel = 500;
// 光线至少弹射次数
const int min_bounce = 45;
// 俄罗斯轮盘赌算法生存概率
const double RR = 0.9;

/*******创建相机*******/
point3 lookfrom(13, 2, 3);
point3 lookat(0, 0, 0);
vec3 vup(0, 1, 0);
auto dist_to_focus = 10.0;
auto aperture = 0.1;

camera cam(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus);

/*******创建场景*******/
auto world = random_scene();

/******渲染部分*****/
// 3通道图像存在一维数组中
unsigned char* odata = (unsigned char*)malloc(image_width * image_height * channel);
unsigned char* p = odata;
for (int j = image_height - 1; j >= 0; --j) {
// 标准错误流显示进度信息,单行刷新显示
std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
#pragma omp parallel for
for (int i = 0; i < image_width; ++i) {
color pixel_color(0, 0, 0);
for (int s = 0; s < samples_per_pixel; ++s) {
// 在像素内部随机采样
auto u = (i + random_double()) / (image_width - 1);
auto v = (j + random_double()) / (image_height - 1);
ray r = cam.get_ray(u, v);
pixel_color += ray_color(r, world, min_bounce, RR);
}
write_color(p, pixel_color, samples_per_pixel);
}
}
stbi_write_png(filepath.c_str(), image_width, image_height, channel, odata, 0);
std::cerr << "\nDone.\n";
}

得到的效果如下:

FinalRender2

---- 本文结束 知识又增加了亿点点!----

文章版权声明 1、博客名称:LycTechStack
2、博客网址:https://lz328.github.io/LycTechStack.github.io/
3、本博客的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主进行删除处理。
4、本博客所有文章版权归博主所有,如需转载请标明出处。