本文主要是介绍《学一辈子光线追踪》 六 正交基,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
蒙特卡洛光线追踪技术系列 见 蒙特卡洛光线追踪技术
在最后一章中,我们开发了生成与日晷相对的随机方向的方法。我们要做的是基于任意曲面的法向量。正交正规基(ONB)是三个相互正交的单位向量的集合。笛卡尔xyz轴就是这样的一个ONB,我有时忘记了它必须坐在某个真实的地方,有真实的方向,才能在真实世界中有意义,而在虚拟世界中有一些虚拟的地方和方向。图片是相机和场景相对位置/方向的结果,只要相机和场景在同一坐标系中描述,一切都是可以的。
假设我们有一个原点o和笛卡尔单位向量x/y/z。当我们说一个位置是(3,-2,7)时,我们实际上是说:
位置为 o + 3*x - 2*y + 7*z
如果我们想测量另一个坐标系中原点为o'且基向量为u/v/w的坐标,我们只需找到数字(u,v,w)即可:
位置是o'+uu+vv+w。
如果你学习图形入门课程,你会花很多时间在坐标系和4x4坐标变换矩阵上。注意,这在图形中是很重要的!但我们不需要它。我们需要的是用相对于n的集合分布生成随机方向。我们不需要原点,因为方向与原点无关。我们需要两个相互垂直于n的余切向量。
有些模型至少会有一个余切向量。制作ONB的最困难的情况是我们只有一个向量。假设我们有任何不为零长或不平行于n的向量a,我们可以利用 cross(c,d) 同时垂直于c和d的叉积的性质得到垂直于n的向量s和t:
t = unit_vector( cross(a, n) )
s = cross(t,n)
关键是,我们没有a,如果我们在某个点上选择一个特定的a,我们将得到一个与a平行的n。一个常见的方法是使用if语句来确定n是否是一个特定的轴,如果不是,则使用该轴。
If (fabs(n.x()) > 0.9)a = (0,1,0)
elses = (1,0,0)
一旦我们有一个ONB,并且我们有一个相对于z轴的随机向量 (x,y,z) ,(该项量在原始坐标系中的值是(x,y,z))我们就可以得到相对于n的向量:
Random vector = x*s + y*t + z*n
你可能会注意到我们用了类似的数学方法从相机获取光线。这可以看作是对相机自然坐标系的改变。我们应该为ONB创建一个类还是实用函数足够了?我不确定,但让我们创建一个类,因为它不会比实用函数更复杂:
#ifndef __ONB_H__
#define __ONB_H__
#include "vec3.h"
class onb {
public:onb(){}inline vec3 operator[](int i)const { return axis[i]; }vec3 u()const { return axis[0]; }vec3 v()const { return axis[1]; }vec3 w()const { return axis[2]; }vec3 local(float a, float b, float c)const { return a*u() + b*v() + c*w(); }vec3 local(const vec3&a)const { return a.x()*u() + a.y()*v() + a.z()*w(); }void build_from_w(const vec3&);vec3 axis[3];
};
void onb::build_from_w(const vec3&n) {axis[2] = unitVector(n);vec3 a;if (fabs(w().x()) > 0.9)a = vec3(0, 1, 0);elsea = vec3(1, 0, 0);axis[1] = unitVector(cross(w(),a));axis[0] = cross(w(), v());
}
#endif
我们可以用这个重写Lambertian材料,得到:
inline vec3 random_cosine_direction() {float r1 = myRandom();float r2 = myRandom();float z = sqrt(1 - r2);float phi = 2 * M_PI*r1;float x = cos(phi) * 2 * sqrt(r2);float y = sin(phi) * 2 * sqrt(r2);return vec3(x, y, z);
}
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& alb, ray& scattered, float &pdf)const {onb uvw;uvw.build_from_w(rec.normal);vec3 direction = uvw.local(random_cosine_direction());scattered = ray(rec.p, unitVector(direction), r_in.time());alb = albedo->value(rec.u, rec.v, rec.p);pdf = dot(uvw.w(), unitVector(scattered.direction())) / M_PI;//return true;
}
得到结果:
这个结果对吗?我们还不能确定。在缺乏可靠的参考解决方案的情况下,追踪错误是很困难的。让我们暂时把它搁置一下,然后继续消除一些噪音。
这篇关于《学一辈子光线追踪》 六 正交基的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!