PBR读书笔记二:Basic Shapes

在整个图形学领域,空间中的物体都是由基本的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)的内容,不作为重点赘述。

光线与包围盒的相交

对于一个定义\(\vec r = o + t\vec d\)的光线,假设其与平面\(ax+by+cz+d = 0\)相交,可有解为\(t = \frac{-\vec d-((a,b,c)\cdot o)}{((a,b,c)\cdot \vec d)}\),而对于由\(x\)决定的平面,则可以进一步地简写为:\(t_0=\frac{x_0-o_x}{d_x}\)

则相应地,我们的代码如下:

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::maxstd::min会好一些

作者

Carbene Hu

发布于

2021-12-30

更新于

2022-08-19

许可协议

评论