《Ray Tracing in One Weekend》笔记 - 【Chapter 6】:反走样处理

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)
四个点的颜色值

结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值