Search

Final Scene

Created
2021/03/30
Tags
Chapter 13
RT에 기본적으로 사용 될 수 있는 모든 특징들을 구현했기 때문에, 이번 Chapter에서는 특별히 어떤 특징을 더 구현하지는 않을 것이다. 대신에 우리가 만든 코드를 이용하여 멋진 world를 만들어보자.
수정된 main.cpp는 아래와 같다.
#include "rtweekend.h" #include "color.h" #include "hittable_list.h" #include "sphere.h" #include "camera.h" #include "vec3.h" #include "material.h" #include <iostream> color ray_color(const ray& r, const hittable& world, int depth) { hit_record rec; // If we've exceeded the ray bound limit, no more light is gathered. if (depth <= 0) return (color(0, 0, 0)); if (world.hit(r, 0.001, infinity, rec)) { ray scattered; color attenuation; if (rec.mat_ptr->scatter(r, rec, attenuation, scattered)) return (attenuation * ray_color(scattered, world, depth - 1)); return (color(0, 0, 0)); } vec3 unit_direction = unit_vector(r.direction()); auto t = 0.5 * (unit_direction.y() + 1.0); return (1.0 - t) * color(1.0, 1.0, 1.0) + t * color(0.5, 0.7, 1.0); } hittable_list random_scene() { hittable_list world; auto ground_material = make_shared<lambertian>(color(0.5, 0.5, 0.5)); world.add(make_shared<sphere>(point3(0, -1000, 0), 1000, ground_material)); for (int a = -11; a < 11; ++a) { for (int b = -11; b < 11; ++b) { auto choose_mat = random_double(); point3 center(a + 0.9 * random_double(), 0.2, b + 0.9 * random_double()); if ((center - point3(4, 0.2, 0)).length() > 0.9) { shared_ptr<material> sphere_material; if (choose_mat < 0.8) { // diffuse auto albedo = color::random() * color::random(); sphere_material = make_shared<lambertian>(albedo); world.add(make_shared<sphere>(center, 0.2, sphere_material)); } else if (choose_mat < 0.95) { // metal auto albedo = color::random(0.5, 1); auto fuzz = random_double(0, 0.5); sphere_material = make_shared<metal>(albedo, fuzz); world.add(make_shared<sphere>(center, 0.2, sphere_material)); } else { // glass sphere_material = make_shared<dielectric>(1.5); world.add(make_shared<sphere>(center, 0.2, sphere_material)); } } } } auto material1 = make_shared<dielectric>(1.5); world.add(make_shared<sphere>(point3(0, 1, 0), 1.0, material1)); auto material2 = make_shared<lambertian>(color(0.4, 0.2, 0.1)); world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2)); auto material3 = make_shared<metal>(color(0.7, 0.6, 0.5), 0.0); world.add(make_shared<sphere>(point3(4, 1, 0), 1.0, material3)); return (world); } int main(void) { // Image const auto aspect_ratio = 3.0 / 2.0; const int image_width = 1200; const int image_height = static_cast<int>(image_width / aspect_ratio); const int samples_per_pixel = 500; const int max_depth = 50; // World auto world = random_scene(); // Camera point3 lookfrom(13, 2, 3); point3 lookat(0, 0, 0); vec3 vup(0, 1, 0); auto dist_to_focus = 10.0; auto aperture = 0.1; camera cam(lookfrom, lookat, vup, 20.0, aspect_ratio, aperture, dist_to_focus); // Render std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; for (int j = image_height - 1; j >= 0; --j) { std::cerr << "\rScanlines Remaining: " << j << ' ' << std::flush; for (int i = 0; i < image_width; ++i) { color pixel_color(0, 0, 0); for (int s = 0; s < samples_per_pixel; ++s) { auto u = (i + random_double()) / (image_width - 1); auto v = (j + random_double()) / (image_height - 1); ray r = cam.get_ray(u, v); pixel_color += ray_color(r, world, max_depth); } write_color(std::cout, pixel_color, samples_per_pixel); } } std::cerr << "\nDone.\n"; return (0); }
C++
코드를 실행해보면 아래와 같이 책 커버에 있는 Image를 얻을 수 있다. (Sample 횟수가 꽤 높아서 Render되는데 꽤 오랜 시간이 걸린다. 약 8시간 정도 소요되었다.)
마지막으로 정말 흥미로운 사실을 위 그림을 통해 알 수 있는데, 유리공으로 나타난 Object는 그림자를 갖지 않아 공중에 떠있는 느낌을 준다는 것이다. 이는 코드 상의 버그는 아니다. 실생활에서 유리 공을 볼일이 많지는 않을 것인데, 실제로 보아도 조금은 이상하기도 하고 흐린 날에보면 떠있는 것처럼 보이기도 한다. 또한 하늘을 막아두지 않은 상태이므로 유리공 아래의 큰 구체의 한 점에서는 여전히 많은 빛들이 닿게 된다는 것도 알 수 있다.