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

tech2023-05-19  97

本文主要参照 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); }
最新回复(0)