Closed xiaomx32 closed 2 months ago
您好, 是这样的, samllpt_rewrite.cpp 的代码有很多简化的地方, 它的相机压缩了中间的坐标变换, 直接把图像平面的坐标变换到世界空间的光线了.
我注释了一下 ray tracing in one weekend 中 Listing 64: [camera.h] Positionable and orientable camera
的代码, 您可以发现两者其实是一样的:
class camera {
public:
camera(
point3 lookfrom,
point3 lookat,
vec3 vup,
double vfov, // vertical field-of-view in degrees
double aspect_ratio
) {
auto theta = degrees_to_radians(vfov);
auto h = tan(theta/2);
auto viewport_height = 2.0 * h;
auto viewport_width = aspect_ratio * viewport_height;
auto w = unit_vector(lookfrom - lookat); // front
auto u = unit_vector(cross(vup, w)); // right
auto v = cross(w, u); // up
origin = lookfrom;
horizontal = viewport_width * u;
vertical = viewport_height * v;
lower_left_corner = origin - horizontal/2 - vertical/2 - w;
}
ray get_ray(double s, double t) const {
return ray(origin, lower_left_corner + s * horizontal + t * vertical - origin);
// for `lower_left_corner + s * horizontal + t * vertical - origin`
// => s * horizontal + t * vertical - horizontal/2 - vertical/2 - w
// => (s-0.5) * horizontal + (t-0.5) * vertical - w
// => (s-0.5) * viewport_width * u + (t-0.5) * viewport_height * v - w
// => (s-0.5) * aspect_ratio * 2.0 * tan_fov * u + (t-0.5) * 2.0 * tan_fov * v - w
// same to `front + right * (s - 0.5) + up * (0.5 - t)` in `samllpt_rewrite.cpp`
}
private:
point3 origin;
point3 lower_left_corner;
vec3 horizontal;
vec3 vertical;
};
在这里 samllpt_rewrite.cpp 和 ray tracing in one weekend 还有些细节上的差异, 比如 samllpt_rewrite.cpp 从上往下遍历图像竖直方向, 使用左手的相机坐标系; ray tracing in one weekend 从下往上遍历, 使用右手系等.
因为 samllpt_rewrite.cpp 和 ky.cpp 主要想解释的是积分器, 所以只实现了一个简单的针孔相机, 和 pbrt 的代码对不上, 但它们的原理仍然是一样的. 后者的相机阅读起来有些费脑筋🙄, 我记过一点笔记: camera.h, perspective.cpp, 您有兴趣的话可以看看.
have fun~
感谢您的解答。看完您的推导后,发现相机的构造确实是一样的。 在 ray tracing in one weekend 中 horizontal 和 viewport_width 表示的意思是一样的,所以对我这样的读者造成了一定的误解。其中,没有将点、向量、标量长度严格区分开,也不是一个好习惯。不过很感谢您的笔记,帮了我很多,谢谢。 祝您生活愉快!
在透视相机的构造函数中有这样两行代码:
right = Normalize(Cross(front, up)) * tan_fov * Aspect();
this->up = Normalize(Cross(right, front)) * tan_fov;
请问,在构造
right
、up
时,为什么还有乘以tan_fov
和Aspect()
呢? PS :我看过 ray tracing in one weekend 和 pbrt 的相机部分,感觉两个相差很大,您设计相机感觉和前者相似,但还是有些不太一样:似乎“视口”和“最终图像”合二为一了,是这样吗?