【光线追踪系列九】物体动态模糊

本文主要参照 Ray Tracing: The Next Week,其中只是主要精炼光追相关理论,具体实现可参照原文。
在这里插入图片描述

一、动态模糊

如果要实动态模糊的效果,可以将原来的球体,改成球心在某条线段上的球体,例如代码中将sphere修改为moving_sphere,并将原来的center修改成center0, center1。每条射线都会有一个随机的系数t(范围0到1),使用t插值center0, center1,得到这条线段上的某个点作为moving_sphere的球心。

不同的射线会有不同的t,不同的t插值出来的球心位置就会不同。对某个像素随机采样ns次之后,这个像素就会产生ns条t值随机的射线,这ns条射线对应位置不同的球,从而渲染出一个模糊的像素。渲染这条线段附近区域的包含该球体的所有像素,就能看到球在这条线段上运动的模糊效果,从而模拟相机快门的长曝光时间。

ray增加参数:

class ray
{
public:
	vec3 A; //起点
	vec3 B; //方向
	float _time;
	ray() {}
	ray(const vec3 &a, const vec3 &b, float ti=0.0f)
	{
		A = a;
		B = b;
		_time = ti;
	}
	float time() const { return _time; }
	vec3 origin() const { return A; }
	vec3 direction() const { return B; }
	vec3 point_at_parameter(float t) const { return A + t * B; } //终点的坐标
};

camera增加随机产生time赋值给ray:

class camera
{
public:
	vec3 origin;
	vec3 lower_left_corner;
	vec3 horizontal;
	vec3 vertical;
	vec3 u, v, w;
	float lens_radius;
	float time0, time1;
	//lookfrom为相机位置,lookat为观察位置,vup传(0,1,0),vfov为视野角度,aspect为屏幕宽高比
	//aperture为光圈大小,focus_dist为相机到观察点的距离
	camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect, float aperture, float focus_dist, float t0, float t1)
	{
		time0 = t0;
		time1 = t1;
		lens_radius = aperture / 2;
		float theta = vfov * M_PI / 180;
		float half_height = tan(theta / 2);
		float half_width = aspect * half_height;
		origin = lookfrom;
		w = unit_vector(lookfrom - lookat);
		u = unit_vector(cross(vup, w));
		v = cross(w, u);
		lower_left_corner = origin - half_width * focus_dist * u - half_height * focus_dist * v - focus_dist * w;
		horizontal = 2 * half_width * focus_dist * u;
		vertical = 2 * half_height * focus_dist * v;
	}

	ray get_ray(float s, float t)
	{
		vec3 rd = lens_radius * random_in_unit_disk();
		vec3 offset = u * rd.x() + v * rd.y();
		float time = time0 + random_double() * (time1 - time0);
		return ray(origin + offset, lower_left_corner + s * horizontal + t * vertical - origin - offset, time);
	}

};

moving_sphere类:

class moving_sphere : public hittable
{
public:
	vec3 center0, center1;
	float time0, time1;
	float radius;
	material *mat_ptr; /* NEW */
	vec3 center(float time) const
	{
		return center0 + ((time - time0) / (time1 - time0)) * (center1 - center0);
	}
	moving_sphere() {}
	moving_sphere(
		vec3 cen0, vec3 cen1, double t0, double t1, double r, material *m)
		: center0(cen0), center1(cen1), time0(t0), time1(t1), radius(r), mat_ptr(m)
	{};
	
	//如果命中了,命中记录保存到rec
	virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const
	{
		vec3 oc = r.origin() - center(r.time());
		float a = dot(r.direction(), r.direction());
		float b = dot(oc, r.direction());
		float c = dot(oc, oc) - radius * radius;
		float discriminant = b * b - a * c;
		if (discriminant > 0)
		{
			float temp = (-b - sqrt(discriminant)) / a; //小实数根
			if (temp < t_max && temp > t_min)
			{
				rec.t = temp;
				rec.p = r.point_at_parameter(rec.t);
				rec.normal = (rec.p - center(r.time())) / radius;
				rec.mat_ptr = mat_ptr; /* NEW */
				return true;
			}
			temp = (-b + sqrt(discriminant)) / a; //大实数根
			if (temp < t_max && temp > t_min)
			{
				rec.t = temp;
				rec.p = r.point_at_parameter(rec.t);
				rec.normal = (rec.p - center(r.time())) / radius;
				rec.mat_ptr = mat_ptr; /* NEW */
				return true;
			}
		}
		return false;
	}
};

放置球体:

camera cam(lookfrom, lookat, vec3(0, 1, 0), 20, float(nx) / float(ny), aperture, dist_to_focus,0,0.5);


hittable *random_scene() {
	int n = 500;
	hittable **list = new hittable*[n + 1];
	list[0] = new sphere(vec3(0, -1000, 0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)));
	int i = 1;
	for (int a = -11; a < 11; a++) {
		for (int b = -11; b < 11; b++) {
			float choose_mat = random_double();
			vec3 center(a + 0.9*random_double(), 0.2, b + 0.9*random_double());
			if ((center - vec3(4, 0.2, 0)).length() > 0.9) {
				if (choose_mat < 0.8) {  // diffuse
					if (b % 2 == 0) //动态模糊的球体
					{
						auto center2 = center + vec3(0, random_double(), 0);
						list[i++] = new moving_sphere(center, center2, 0.0, 1.0, 0.2,
							new lambertian(vec3(random_double()*random_double(),
								random_double()*random_double(),
								random_double()*random_double())
							)
						);
					}
					else
					{
						list[i++] = new sphere(center, 0.2,
							new lambertian(vec3(random_double()*random_double(),
								random_double()*random_double(),
								random_double()*random_double())
							)
						);
					}
				}
				else if (choose_mat < 0.95) { // metal
					list[i++] = new sphere(center, 0.2,
						new metal(vec3(0.5*(1 + random_double()),
							0.5*(1 + random_double()),
							0.5*(1 + random_double())),
							0.5*random_double()));
				}
				else {  // glass
					list[i++] = new sphere(center, 0.2, new dielectric(1.5));
				}
			}
		}
	}

	list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5));
	list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
	list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));

	return new hittable_list(list, i);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值