Ray Tracing in One Weekend 笔记 - Chapter6:抗锯齿处理
在之前的操作中,只对每个像素点的(0,0)的位置做了一次采样,并用这个点的颜色值代表了整个像素的颜色,因而会有较明显的锯齿感。
本节中,对一个像素点的不同位置进行多次采样,对这些采样值取平均操作,从而获得最后代表该像素点的颜色值。
该方法也就是常说的MSAA方方法,书中采用的采样方法是对一个像素点的不同位置进行随机采样。
未作抗锯齿处理放大8倍的结果
1. 抽象出一个摄像机类
#ifndef CAMERAH
#define CAMERAH
#include "ray.h"
class camera {
public:
camera() {
lower_left_corner = vec3(-2.0, -1.0, -1.0);
horizontal = vec3(4.0, 0.0, 0.0);
vertical = vec3(0.0, 2.0, 0.0);
origin = vec3(0.0, 0.0, 0.0);
}
ray get_ray(float u, float v) { return ray(origin, lower_left_corner + u * horizontal + v * vertical); }
vec3 origin;
vec3 lower_left_corner;
vec3 horizontal;
vec3 vertical;
};
#endif
2. 对每个像素点进行多次采样
#include <iostream>
#include <fstream>
#include "vec3.h"
#include "ray.h"
#include "hitable_list.h"
#include "sphere.h"
#include <float.h>
#include "camera.h"
// -------- color 函数用于返回背景的颜色 -------- //
vec3 color(const ray& r, hitable *world) {
hit_record rec;
if (world->hit(r, 0.0, FLT_MAX, rec)) {
return 0.5 * vec3(rec.normal.x() + 1, rec.normal.y() + 1, rec.normal.z() + 1);
}
else {
vec3 unit_direction = unit_vector(r.getDirection());
float t = 0.5 * (unit_direction.y()) + 1.0;
return (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
}
}
void main() {
int nx = 200;
int ny = 100;
int ns = 100; // 每个像素点的随机采样次数
std::ofstream outfile("PPMTest.txt", std::ios_base::out);
outfile << "P3\n" << nx << " " << ny << "\n255\n";
//std::cout << "P3\n" << nx << " " << ny << "\n255\n";
hitable *list[2];
list[0] = new sphere(vec3(0,0,-1), 0.5);
list[1] = new sphere(vec3(0, -100.5, -1), 100); // 在半部分放一个大球作为地面
hitable *world = new hitable_list(list, 2);
camera cam;
bool randSample = true;
for (int j = ny - 1; j >= 0; --j) {
for (int i = 0; i < nx; ++i) {
vec3 col = vec3(0,0,0);
if (randSample) {
// 随机采样
for (int s = 0; s < ns; ++s) {
// 对每一个像素点随机采样100次
float u = float(i + (rand() % 101) / 100.0) / float(nx);
float v = float(j + (rand() % 101) / 100.0) / float(ny);
ray r = cam.get_ray(u, v);
vec3 p = r.getPointAtParameter(2.0);
col += color(r, world);
}
col /= float(ns);
}
else {
// 固定点采样
float u0 = float(i + 0.25) / float(nx);
float u1 = float(i + 0.75) / float(nx);
float v0 = float(j + 0.25) / float(ny);
float v1 = float(j + 0.75) / float(ny);
col = color(cam.get_ray(u0, v0), world)
+ color(cam.get_ray(u1, v0), world)
+ color(cam.get_ray(u0, v1), world)
+ color(cam.get_ray(u1, v1), world);
col /= 4.0;
}
int ir = int(255.99 * col[0]);
int ig = int(255.99 * col[1]);
int ib = int(255.99 * col[2]);
outfile << ir << " " << ig << " " << ib << "\n";
std::cout << ir << " " << ig << " " << ib << "\n";
}
}
}
(1)随机采样
书中对每个像素点中随机采样100次,而后再对100次取得的像素值取平均。
利用rand() 函数生成随机数
若需要产生 0 ~ 99 中的一个随机整数,表达式可以为
int random = rand() % 100
故要生成一个保留到百分位的 0 ~ 1 之间的小数,可以表示为
float random = (rand() % 101) / 100.0;
结果
(2)固定点采样
这里对于每个像素点,提取了其中
(0.25, 0.25)
(0.25, 0.75)
(0.75, 0.25)
(0.75, 0.75)
四个点的颜色值
结果