RayTrace in the rest of your life
蒙特卡洛积分
其大致内容大家可以自行去搜索,还是比较直观。上面的连接讲了不同的函数使用蒙特卡洛的例子
使用重要性采样
这里的重要性采样是通过pdf的值来决定的。这里有一个混淆点,一个是scatterPDF一个是SamplePDF,scatterPDF我们可以理解为albedo的属性,就是反射率(或者理解为,光线从一个方向过来后,从这个方向射出去的能量剩余值),比如diffuse材质的为1 / pi。而SamplePDF的表示采样这个方向的radiance 的概率。
设置lambertian材质
这里的lambertian材质,scatter的方向概率为C⋅cos(θo)
class lambertian : public material{
public:
lambertian(const color& albedo) :tex(make_shared<solid_color>(albedo)){}
lambertian(shared_ptr<texture> tex) : tex(tex){}
bool scatter(
const Ray& r_in,const hit_record& rec,color& attenuation,Ray& scattered
) const override{
vec3 direction = rec.normal + random_unit_vector();
if(direction.near_zero()) direction = rec.normal;
direction = unit_vector(direction);
scattered = Ray(rec.p , direction, r_in.time());
attenuation = tex->value(rec.u,rec.v,rec.p);
return true;
}
double scattering_pdf(const Ray& r_in, const hit_record& rec, const Ray& scattered)
const override
{
auto cosine = dot(rec.normal, unit_vector(scattered.direction()));
return cosine < 0 ? 0 : cosine / pi;
}
private:
color albedo;
shared_ptr<texture> tex;
};
double scatter_pdf = rec.mat->scattering_pdf(r, rec, scattered);
double sample_pdf = scatter_pdf;
color color_from_scatter = (scatter_pdf * attenuation * ray_color(scattered,depth-1,world)) / sample_pdf;
return color_from_emission + color_from_scatter;
这里使用相同的pdf,或者你也可以使用均匀的pdf
double sample_pdf = 1.0 / (2 * pi);
但是我们的采样的方式并不是在交点处的半球内均匀的采样,而是依据normal来在一个球内采样。于是我们可以更换采样的方式
vec3 direction = random_on_hemisphere(rec.normal);
inline vec3 random_on_hemisphere(const vec3& normal){
vec3 on_unit_sphere = random_unit_vector();
if(dot(normal,on_unit_sphere) > 0.0){
return on_unit_sphere;
}
else{
return -on_unit_sphere;
}
}
生成随机方向
相对于Z轴的随机方向生成
文章中的意思我理解了一下,就是我们有两个采样的方向,一个是方位角一个是天顶角,不管是哪个的采样,其采样是独立的但是他们的概率都是1.于是我们需要在0到1的范围内进行采样.首先我们来看天顶角。其采样的概率为1 / 2Π。我们计算到指定的r1的概率的CDF得到下面的推算(CDF就是到指定的角度的概率只和也就是一个概率密度的积分)
于是我们可以推出对应的天顶角为
而对于方位角其概率密度的公式为
我们假设球体密度均匀,此时的的概率密度 = p(w) = 1 / 4 Π
最后推算出这个角度,以及对应的笛卡尔坐标,得到我们半球上的随机点
Uniform sampling a Hemisphere
之前是在球体中采样,但是实际上我们的射线需要在半球上进行采样。当半球的密度是均匀的时候,就会得到下面的方位角
Cosine Sampling a Hemisphere
文章中将pdf更改为p(ω)=f(θ)=cos(θ)/π
通过此PDF就可以得到一个采样的方式
inline vec3 random_cosine_direction() {
auto r1 = random_double();
auto r2 = random_double();
auto phi = 2*pi*r1;
auto x = std::cos(phi) * std::sqrt(r2);
auto y = std::sin(phi) * std::sqrt(r2);
auto z = std::sqrt(1-r2);
return vec3(x, y, z);
}