【Ray-Tracing In Next Week】第8章 体渲染(Volume)

    xiaoxiao2025-08-05  21

    本节讨论体数据,下面是渲染效果:

    代码使用VS2015编写,从如下链接下载:

    链接:https://pan.baidu.com/s/1S8lrcyLnhl8nNKZB9svXMg  提取码:5ayj  【具体实现】

    首先要讲关于体数据的一些基本概念,一个体数据比如雾、烟、云,光可以射入其中,在其中可以散射等。体渲染是个大课题,本节我们实现最基本的体渲染。首先要明确:

    1、光线射入到体当中,行进的距离与密度成反比。

    2、光线射入到体当中,发生碰撞的光的下一个方向是任意的,不像碰到金属物体发生任意方向的反射(其实不是任意的,它不可能指向金属内部),而光线在体中传递碰撞的方向是任意的。

    因此我们定义体的材质isotropic

    class isotropic : public material { public: isotropic(texture* tex):_albedo(tex){} virtual bool scatter(const ray& InRay, const hit_record& info, vec3& attenuation, ray& scattered) const { scattered = ray(info.p, random_in_unit_disk()); attenuation = _albedo->value(info.u, info.v, info.p); return true; } texture* _albedo; };

    散射的方向是使用了random_in_unit_disk就是方向是以单为球为原型随机的。

    其二我们定义体数据constant_medium,看它的hit函数:

    首先求了射入体与射出体的距离distance_inside_boundary。其次随机了一个光在体中的传输距离hit_distance,可以看到其与密度呈反比。这是最简单的体模型。

    virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const { bool db = (drand48() < 0.00001); db = false; hit_record rec1, rec2; if (boundary->hit(r, -FLT_MAX, FLT_MAX, rec1)) //直线与盒子的近交点 { if (boundary->hit(r, rec1.t + 0.0001f, FLT_MAX, rec2)) //直线与盒子远点的交点 { if (rec1.t < t_min) rec1.t = t_min; if (rec2.t > t_max) rec2.t = t_max; if (rec1.t >= rec2.t) return false; //以上三个if确保交于体且位于体内 if (rec1.t < 0) rec1.t = 0; //光线与体的交点的起点与终点之间的长度 float distance_inside_boundary = (rec2.t - rec1.t) * r.direction().length(); //hit_distance是光线在体中传输的距离,可以看到与密度成反比,密度越大,传输距离越短,使用一个随机数的log //表达随机的传输距离,但是整体与密度呈反比 float hit_distance = -(1 / density)*log(drand48()); if (hit_distance < distance_inside_boundary) { rec.t = rec1.t + hit_distance / r.direction().length(); rec.p = r.point_at_parameter(rec.t); rec.normal = unit_vector(vec3(drand48(), drand48(), drand48())); //随机的法线方向 rec.mat_ptr = phase_function; return true; } } } return false; }

    最后我们在BOX中定义两个体数据:

    hitable* cornell_box() { hitable** list = new hitable*[8]; int i = 0; material *red = new lambertian(new constant_texture(vec3(0.65f, 0.05f, 0.05f))); material *white = new lambertian(new constant_texture(vec3(0.73f, 0.73f, 0.73f))); material *green = new lambertian(new constant_texture(vec3(0.12f, 0.45f, 0.15f))); material *light = new diffuse_light(new constant_texture(vec3(7, 7, 7))); list[i++] = new flip_normals(new yz_rect(0.0f, 555.0f, 0.0f, 555.0f, 555.0f, green)); list[i++] = new yz_rect(0.0f, 555.0f, 0.0f, 555.0f, 0.0f, red); list[i++] = new xz_rect(113, 443, 127, 432, 554, light); list[i++] = new flip_normals(new xz_rect(0.0f, 555.0f, 0.0f, 555.0f, 555.0f, white)); list[i++] = new xz_rect(0.0f, 555.0f, 0.0f, 555.0f, 0.0f, white); list[i++] = new flip_normals(new xy_rect(0.0f, 555.0f, 0.0f, 555.0f, 555.0f, white)); hitable* b1 = new translate(new rotate_y(new box(vec3(0, 0, 0), vec3(165, 165, 165), white), -18), vec3(130, 0, 65)); hitable* b2 = new translate(new rotate_y(new box(vec3(0, 0, 0), vec3(165, 330, 165), white), 15), vec3(265, 0, 295)); list[i++] = new constant_medium(b1, 0.01f, new constant_texture(vec3(1.0f, 1.0f, 1.0f))); list[i++] = new constant_medium(b2, 0.01f, new constant_texture(vec3(0.0f, 0.0f, 0.0f))); return new hitable_list(list, i); }

     

    最新回复(0)