当前位置:   article > 正文

光线追踪11 - Positionable Camera(可定位相机)

光线追踪11 - Positionable Camera(可定位相机)

相机和介质一样,调试起来很麻烦,所以我总是逐步开发我的相机。首先,我们允许可调节的视野(fov)。这是渲染图像从一边到另一边的视觉角度。由于我们的图像不是正方形的,水平和垂直的视野是不同的。我总是使用垂直视野。通常我会用角度来指定,然后在构造函数内部转换为弧度 — 这只是个人喜好的问题。

12.1 Camera Viewing Geometry
 首先,我们将保持从原点出发并指向z = -1平面的光线。我们可以将其设置为z = -2平面,或任何其他平面,只要我们将h与该距离成比例即可。以下是我们的设置:

Figure 18: Camera viewing geometry (from the side)

This implies  h = tan\frac{\theta }{2} , Our camera now becomes:

  1. class camera {
  2. public: double aspect_ratio = 1.0; // Ratio of image width over height
  3. int image_width = 100; // Rendered image width in pixel count
  4. int samples_per_pixel = 10; // Count of random samples for each pixel
  5. int max_depth = 10; // Maximum number of ray bounces into scene
  6. double vfov = 90; // Vertical view angle (field of view)
  7. void render(const hittable& world) {
  8. ...
  9. private:
  10. ...
  11. void initialize() {
  12. image_height = static_cast<int>(image_width / aspect_ratio);
  13. image_height = (image_height < 1) ? 1 : image_height;
  14. center = point3(0, 0, 0);
  15. // Determine viewport dimensions.
  16. auto focal_length = 1.0;
  17. auto theta = degrees_to_radians(vfov);
  18. auto h = tan(theta/2);
  19. auto viewport_height = 2 * h * focal_length;
  20. auto viewport_width=viewport_height*(static_cast<double>(image_width)/image_height);
  21. // Calculate the vectors across the horizontal and down the vertical viewport edges.
  22. auto viewport_u = vec3(viewport_width, 0, 0);
  23. auto viewport_v = vec3(0, -viewport_height, 0);
  24. // Calculate the horizontal and vertical delta vectors from pixel to pixel.
  25. pixel_delta_u = viewport_u / image_width;
  26. pixel_delta_v = viewport_v / image_height;
  27. // Calculate the location of the upper left pixel.
  28. auto viewport_upper_left =
  29. center - vec3(0, 0, focal_length) - viewport_u/2 - viewport_v/2; pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
  30. }
  31. ...
  32. };

Listing 74: [camera.h] Camera with adjustable field-of-view (fov)


我们将使用一个90°的视野来测试这些变化,以两个相互接触的球体构成的简单场景为例。

  1. int main() {
  2. hittable_list world;
  3. auto R = cos(pi/4);
  4. auto material_left = make_shared<lambertian>(color(0,0,1));
  5. auto material_right = make_shared<lambertian>(color(1,0,0));
  6. world.add(make_shared<sphere>(point3(-R, 0, -1), R, material_left));
  7. world.add(make_shared<sphere>(point3( R, 0, -1), R, material_right));
  8. camera cam;
  9. cam.aspect_ratio = 16.0 / 9.0;
  10. cam.image_width = 400;
  11. cam.samples_per_pixel = 100;
  12. cam.max_depth = 50;
  13. cam.vfov = 90;
  14. cam.render(world);
  15. }

得到渲染结果:

Image 19: A wide-angle view

12.2 Positioning and Orienting the Camera(定位和定向相机)

为了获得任意的viewpoint,让我们首先给出我们关心的点的名称。我们将摄像机放置的位置称为"lookfrom",我们注视的点称为"lookat"。(稍后,如果需要,可以定义一个注视方向而不是注视点。)
我们还需要一种方式来指定摄像机的倾斜角度,也就是绕"lookat-lookfrom"轴的旋转。另一种思考方式是,即使保持"lookfrom"和"lookat"不变,你仍然可以围绕你的鼻子旋转头部。我们需要的是一种为摄像机指定"up"向量的方法。

Figure 19: Camera view direction


        我们可以指定任何一个up向量,只要它不与视线方向平行。将这个up向量投影到与视线方向正交的平面上,得到一个相对于相机的up向量。我使用常见的约定将其命名为“view up”(vup)向量。经过几次叉乘和向量归一化,我们现在有了一个完整的正交基(u、v、w),用于描述相机的方向。u是指向相机右侧的单位向量,v是指向相机上方的单位向量,w是指向视线方向相反的单位向量(由于我们使用右手坐标系),相机中心位于原点。

Figure 20: Camera view up direction


与以前一样,当我们的固定相机面向-Z时,我们的任意视角相机面向-w。请记住,我们可以选择使用世界坐标系的上方向(0,1,0)来指定vup,但不是必须的。这种方法很方便,可以让你的相机在水平方向保持平稳,直到你决定尝试一些疯狂的相机角度为止。

  1. class camera {
  2. public:
  3. double aspect_ratio = 1.0; // Ratio of image width over height
  4. int image_width = 100; // Rendered image width in pixel count
  5. int samples_per_pixel = 10; // Count of random samples for each pixel
  6. int max_depth = 10; // Maximum number of ray bounces into scene
  7. double vfov = 90; // Vertical view angle (field of view)
  8. point3 lookfrom = point3(0,0,-1); // Point camera is looking from
  9. point3 lookat = point3(0,0,0); // Point camera is looking at
  10. vec3 vup = vec3(0,1,0); // Camera-relative "up" direction
  11. ...
  12. private: int image_height; // Rendered image height
  13. point3 center; // Camera center
  14. point3 pixel00_loc; // Location of pixel 0, 0
  15. vec3 pixel_delta_u; // Offset to pixel to the right
  16. vec3 pixel_delta_v; // Offset to pixel below
  17. vec3 u, v, w; // Camera frame basis vectors
  18. void initialize() {
  19. image_height = static_cast<int>(image_width / aspect_ratio);
  20. image_height = (image_height < 1) ? 1 : image_height;
  21. center = lookfrom;
  22. // Determine viewport dimensions.
  23. auto focal_length = (lookfrom - lookat).length();
  24. auto theta = degrees_to_radians(vfov);
  25. auto h = tan(theta/2);
  26. auto viewport_height = 2 * h * focal_length;
  27. Auto viewport_width = viewport_height * (static_cast<double>(image_width) / image_height);
  28. // Calculate the u,v,w unit basis vectors for the camera coordinate frame.
  29. w = unit_vector(lookfrom - lookat);
  30. u = unit_vector(cross(vup, w));
  31. v = cross(w, u);
  32. // Calculate the vectors across the horizontal and down the vertical viewport edges.
  33. vec3 viewport_u = viewport_width * u; // Vector across viewport horizontal edge
  34. vec3 viewport_v = viewport_height * -v; // Vector down viewport vertical edge
  35. // Calculate the horizontal and vertical delta vectors from pixel to pixel.
  36. pixel_delta_u = viewport_u / image_width;
  37. pixel_delta_v = viewport_v / image_height;
  38. // Calculate the location of the upper left pixel.
  39. auto viewport_upper_left=center-(focal_length*w)-viewport_u/2-viewport_v/2;
  40. pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
  41. }
  42. ...
  43. private:
  44. };

Listing 76: [camera.h] Positionable and orientable camera


我们将回到之前的场景,并使用新的视点:

  1. int main() {
  2. hittable_list world;
  3. auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
  4. auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5));
  5. auto material_left = make_shared<dielectric>(1.5);
  6. auto material_right = make_shared<metal>(color(0.8, 0.6, 0.2), 0.0);
  7. world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
  8. world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
  9. world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
  10. world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left));
  11. world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
  12. camera cam;
  13. cam.aspect_ratio = 16.0 / 9.0;
  14. cam.image_width = 400;
  15. cam.samples_per_pixel = 100;
  16. cam.max_depth = 50;
  17. cam.vfov = 90;
  18. cam.lookfrom = point3(-2,2,1);
  19. cam.lookat = point3(0,0,-1);
  20. cam.vup = vec3(0,1,0);
  21. cam.render(world);
  22. }

Listing 77: [main.cc] Scene with alternate viewpoint

得到:

Image 20: A distant view
 

修改  field of view :
    cam.vfov     = 20;
Listing 78: [main.cc] Change field of view

变为:

Image 21: Zooming in

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/213428
推荐阅读
相关标签
  

闽ICP备14008679号