smallpt详解(三)
本文主要对smallpt的光线跟踪函数进行详细的解释
1. 光线跟踪详细解释
计算法向量,计算折射光线,反射光线等,可以查阅《3D数学基础,图形与游戏开发》
1.1 计算部分
Vec radiance(const Ray &r, int depth, unsigned short *Xi) {
double t; // 与射线相交物体的距离
int id = 0; // 与射线相交物体的id
if (!intersect(r, t, id))
return Vec(); // 如果都没有相交,则返回emisson(0, 0, 0)
const Sphere &obj = spheres[id]; // the hit object
Vec x = r.o + r.d*t, n = (x - obj.position).norm(); // 计算n,球面法向量
Vec nl = n.dot(r.d) < 0 ? n : n*-1, f = obj.color;
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // 找出最大的值
if (++depth>5||!p)
if (erand48(Xi)<p)
f = f*(1 / p); //假设f为(0.5, 0.2, 0.2),那么作者假定这个表面的反射率为f*(1/0.5),也就是颜色值最大的反射率最高(1, 0.4, 0.4)
else
return obj.emission;
// ...
}
1.2 漫反射
if (obj.refl == DIFF) { // 如果物体的反射属性是漫反射
double r1 = 2 * M_PI*erand48(Xi), r2 = erand48(Xi), r2s = sqrt(r2); //取随机数
Vec w = nl, u = ((fabs(w.x)>.1 ? Vec(0, 1) : Vec(1)).cross(w)).norm(), v = w.cross(u); //w,v,u为正交基
Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1 - r2)).norm(); //求得一个随机的漫反射光线,继续迭代
return obj.emission + f.mult(radiance(Ray(x, d), depth, Xi));
}
1.3 镜面反射光
else if (obj.refl == SPEC) // 如果物体的反射属性是漫反射
return obj.emission + f.mult(radiance(Ray(x, r.d - n * 2 * n.dot(r.d)), depth, Xi)); //这个比较简单,只要求得反射光的角度即可
1.4 折射加反射
else {
Ray reflRay(x, r.d - n * 2 * n.dot(r.d)); // 由平行四边形的方法求得反射光的direction
bool into = n.dot(nl)>0; // 判断光线是否是进入球体
double nc = 1, nt = 1.5, nnt = into ? nc / nt : nt / nc, ddn = r.d.dot(nl), cos2t;
if ((cos2t = 1 - nnt*nnt*(1 - ddn*ddn))<0) // 如果求得cos2t<0,就没必要进行折射了。
return obj.emission + f.mult(radiance(reflRay, depth, Xi));
Vec tdir = (r.d*nnt - n*((into ? 1 : -1)*(ddn*nnt + sqrt(cos2t)))).norm(); //折射角的角度
double a = nt - nc, b = nt + nc, R0 = a*a / (b*b), c = 1 - (into ? -ddn : tdir.dot(n));
double Re = R0 + (1 - R0)*c*c*c*c*c, Tr = 1 - Re, P = .25 + .5*Re, RP = Re / P, TP = Tr / (1 - P);
return obj.emission + f.mult(depth>2 ? (erand48(Xi)<P ? // 轮盘赌
radiance(reflRay, depth, Xi)*RP : radiance(Ray(x, tdir), depth, Xi)*TP) :
radiance(reflRay, depth, Xi)*Re + radiance(Ray(x, tdir), depth, Xi)*Tr);
}
2 加烟雾效果
学习完smallpt之后,看到图形学的书上提到了烟雾效果。
编程实现
#define E_MATH 2.71828
Vector frog_color(0.7, 0.7, 0.7);
inline double f_atmo(double distance) {
return pow(E_MATH, -(0.01 * 0.01* distance * distance));
}
// 然后修改光线反射,折射中的代码
// 在这个实现中,我只在第一层的递归加了烟雾效果
// 修改漫反射的代码
if (depth <= 1) {
double fTemp = f_atmo(distance);
return obj._emission + (radiance(Ray(hit_point, direct), depth)) * fTemp + frog_color*(1 - fTemp);
}
else
return obj._emission + f.mult(radiance(Ray(hit_point, direct), depth));
// 修改反射
if (depth <= 1) {
double fTemp = f_atmo(distance);
return obj._emission + (radiance(Ray(hit_point, direct_refl), depth)) * fTemp + frog_color*(1 - fTemp);
}
else
return obj._emission + radiance(Ray(hit_point, direct_refl), depth);
// 修改折射
double fTemp = f_atmo(distance);
return ((radiance(ray_refl, depth) * Fe
+ radiance(ray_refr, depth) * Fr))*fTemp + frog_color*(1 - fTemp);
效果图1,无烟雾
效果图2,加烟雾,可以看出后面那个大球的轮廓。感觉像现在中国最流行的雾霾。 :D