在整个图形学领域,空间中的物体都是由基本的Shape构成的,比如基本的几何形体:Sphere、Box;或者能够达成更加复杂表现的Mesh等。这一章主要讲述了几种不同的形体的定义和相关计算。
形体基类
PBRT
使用Shape
类来为所有形体创建了一个基类,reverseOrientation
用来决定图形的法线是否翻转(用来确定图形的内、外)。
对于每个形体有如下的基础函数和解释:
1 2
| virtual Bounds3f ObjectBound() const = 0; virtual Bounds3f WorldBound() const;
|
aabb bounding box,用于加速相交求解。
1 2 3 4 5 6 7 8
| virtual bool Intersect(const Ray &ray, Float *tHit, SurfaceInteraction *isect, bool testAlphaTexture = true) const = 0; virtual bool IntersectP(const Ray &ray, bool testAlphaTexture = true) const { Float tHit = ray.tMax; SurfaceInteraction isect; return Intersect(ray, &tHit, &isect, testAlphaTexture); }
|
光线和物体的相交(实际),保证: - 光线未达到终点 - 返回的相交点最近
intersectP
方法用于忽略一些返回值。
1
| virtual Float Area() const = 0;
|
物体的面积,用于计算面积光源。
由于物体不保证封闭,并且光线追踪算法的特殊性,pbrt没有采用背面剔除算法。
1 2 3 4 5 6 7 8 9
| virtual Interaction Sample(const Point2f &u) const = 0; virtual Float Pdf(const Interaction &) const { return 1 / Area(); } virtual Interaction Sample(const Interaction &ref, const Point2f &u) const { return Sample(u); } virtual Float Pdf(const Interaction &ref, const Vector3f &wi) const;
|
剩下的就是和光照有关的重要性采样(Sample)、概率分布函数(pdf)的内容,不作为重点赘述。
光线与包围盒的相交
对于一个定义r=o+td的光线,假设其与平面ax+by+cz+d=0相交,可有解为t=((a,b,c)⋅d)−d−((a,b,c)⋅o),而对于由x决定的平面,则可以进一步地简写为:t0=dxx0−ox。
则相应地,我们的代码如下:
1 2 3
| Float invRayDir = 1 / ray.d[i]; Float tNear = (pMin[i] - ray.o[i]) * invRayDir; Float tFar = (pMax[i] - ray.o[i]) * invRayDir;
|
自然,这两个Near和Far的变量的顺序并不一定正确,于是需要根据两个变量的大小交换,这里需要考虑到浮点数出现0/0导致的NaN
问题,这里利用一条性质:
NaN
浮点数和任何其他浮点数进行比较的返回必定是false
于是更新t0和t1的代码需要仔细一些额外处理(t0、t1是最终返回的值):
1 2
| t0 = tNear > t0 ? tNear : t0; t1 = tFar < t1 ? tFar : t1;
|
(虽然我觉得用stl的std::max
和std::min
会好一些