体渲染——Volume


基本概念

  体渲染(Volume),是绘制类似烟、雾、云的效果。这种渲染和之前的表面渲染不同,光线可以在物体内部进行散射。

体渲染的主要特点

   1. 可以在物体内部散射。

   2. 从进入volume到发生散射的距离,与密度成反比

   3. 光线散射的方向,可以是任意方向

实现

  主要需要解决的问题:在什么位置发生碰撞(scatter),以及scatter ray的方向。

  碰撞的问题在hitable中解决。散射的问题在material中解决。

class constant_medium : public hitable {
public:
	constant_medium(hitable *b, float d, texture *a) : boundary(b), density(d) {
		phase_function = new isotropic(a);
	}
	virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const;
	virtual bool bounding_box(float t0, float t1, aabb& box) const {
		return boundary->bounding_box(t0, t1, box);
	}
	hitable *boundary;
	float density;
	material *phase_function;
};

  碰撞函数:

  先和volume的轮廓求交,确定和轮廓的两个交点,这样体内的碰撞,将发生在两个交点的连线上。

  其在volume内的distance,不会超过上述近交点和远交点的距离,并且与density成反比。

bool constant_medium::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {

	hit_record rec1, rec2;

	//直线与盒子的近交点
	if (boundary->hit(r, -FLT_MAX, FLT_MAX, rec1)) {
		//直线与盒子的远交点
		if (boundary->hit(r, rec1.t + 0.0001, FLT_MAX, rec2)) {

			if (debugging) std::cerr << "\nt0 t1 " << rec1.t << " " << rec2.t << '\n';

			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 (rec1.t < 0)
				rec1.t = 0;
			//近交点和远交点的距离
			float distance_inside_boundary = (rec2.t - rec1.t) * r.direction().length();
			//随机生成传输距离,与密度成反比
			float hit_distance = -(1 / density) * log(random_double());

			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 = vec3(1, 0, 0);  // arbitrary
				rec.normal = unit_vector(vec3(random_double(), random_double(), random_double()));
                                //决定scatter ray的材质
				rec.mat_ptr = phase_function;
				return true;
			}
		}
	}
	return false;
}

  散射函数:
  使用random_in_unit_sphere()表示散射光线为任意方向。

class isotropic : public material {
public:
	isotropic(texture *a) : albedo(a) {}
	virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
                //起点为碰撞点,方向为任意方向
		scattered = ray(rec.p, random_in_unit_sphere(), r_in.time());
		attenuation = albedo->value(rec.u, rec.v, rec.p);
		return true;
	}
	texture *albedo;
};


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM