體渲染——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