
https://raytracing.github.io/books/RayTracingInOneWeekend.html#movingcameracodeintoitsownclass
이거 먼저 하기!
Ray를 일단 카메라에서 뷰포트로 쏘지?
근데 화면 저 멀리에 진~짜 멀리에 8*8사이즈의 검/흰 체스판이 있다고 생각해보셈
Ray를 쏜 후 해당 체스판에 4개의 Ray가 닿았다고 가정해보자
Ray와 접점이 있는 픽셀의 색이 모두 검은색, 모두 흰색, 혹은 반반 등등 섞여있을 것임
근데 실제로 우리가 진~~~짜 멀리있는 체스판을 본다고 가정해보면
검/흰으로 보이는게 아니라, 자동적으로 색이 혼합되어 회색으로 보임
이걸 그래픽스를 통해 해결해야함
그리고 이런 기법을 안티앨리어싱이라고 함
픽셀의 각진 부분이나, 색이 혼합되어야 하는 부분을 적절한 기법을 이용해 색을 만드는거임
픽셀은 원임
사각형이 아님근데 이 BoxFilter 샘플링기법은 픽셀을 사각형이라는 관점으로 바라봄
그래서 픽셀이 도착한 지점을 기준으로 상하좌우 절반씩 확장된 사각형으로 픽셀을 바라본다는거임
그리고 해당 색들의 합의 평균치를 해당 픽셀에 적용시킨다는게 핵심임
이런 기법을 BoxFiltering 기법이라 부르고 SSAA계열의 안티앨리어싱이 이 기법을 사용한 방법임
더 다양한 기법이 있는데
이는 그래픽스 이론책에서 공부할것을 권장!
내가 설명하기엔 너무 길어짐
먼저 픽셀에서 랜덤한 좌표를 구할 랜덤 메서드를 만들음ㅇㅇ
//RTWEEKEND.h ....
inline double random_double()
{
//0~1사이의 랜덤
return std::rand() / (RAND_MAX + 1.0);
}
inline double random_double(double min, double max)
{
return min + (max - min) * random_double();
}
그리고
기본적인 색상은 RGB 0-1값임
픽셀의 색상을 계산 후 이 색상에 왜곡이 일어날 수 있음
double계산이 그럼 ㅇㅇ
그러므로 계산된 색상을 특정 범위내에 고정시켜줄 메서드가 필요함
clamp임ㅇㅇ
clamp는 min과 max범위내에서 되어야 하므로, 이를 구현해둔 MinMaxInterval에서 구현하도록 하겠음ㅇㅇ
class MinMaxInterval {
public:
//...
bool surrounds(double x) const {
return min < x && x < max;
}
double clamp(double x) const
{
if (x < min) return min;
if (x > max) return max;
return x;
}
};
//...
이제 색상을 렌더링하던 메서드에서 색상을 특정 범위내에 잇을 수 있도록 메서드 수정해야함

이렇게 Camera.h에서 사용중인 write_color메서드를 수정해줘야함
//Color.h ...
void write_color(std::ostream& out, const Color& pixel_color) {
double r = pixel_color.x();
double g = pixel_color.y();
double b = pixel_color.z();
//clamping메서드 추가, rgb를 [0-1]사이의 값으로 clamp
static const MinMaxInterval clamping(0.000000, 0.999999);
int rbyte = static_cast<int>(255.999 * clamping.clamp(r));
int gbyte = static_cast<int>(255.999 * clamping.clamp(g));
int bbyte = static_cast<int>(255.999 * clamping.clamp(b));
// Write out the pixel color components.
out << rbyte << ' ' << gbyte << ' ' << bbyte << '\n';
}
이제 픽셀당 샘플수를 결정하고,
해당 샘플수만큼 픽셀에서 랜덤한 위치의 offset(0-1사이)으로 이동한 좌표의 색상을 pick한다음 픽셀의 색으로 변경시키면 된다.
#ifndef CAMERA_H
#define CAMERA_H
#include "Color.h"
#include "hittable.h"
class Camera {
public:
double aspect_ratio = 1.0; // Ratio of image width over height
int image_width = 100; // Rendered image width in pixel count
int samples_per_pixel = 10; //픽셀당 랜덤하게 뽑을 샘플의 수
void render(const Hittable& world) {
initialize();
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j = 0; j < image_height; ++j)
{
std::clog << "\rScanLines remaining: " << (image_height - j) << ' ' << std::flush;
for (int i = 0; i < image_width; ++i)
{
//pixel_color를 구하기
Color pixel_color(0,0,0);
for (int sample = 0; sample < samples_per_pixel; ++sample)
{
Ray r = get_ray(i,j);
pixel_color += ray_color(r, world);
}
write_color(std::cout, pixel_samples_scale * pixel_color);
}
}
std::clog << "\rDone. ";
}
private:
//...
double pixel_samples_scale; //샘플픽셀의 크기, color계산 후 곱해서 해당 픽셀 blurry하게 색상 만들기
void initialize()
{
//....
pixel_samples_scale = 1.0 / samples_per_pixel;
camera_center = Point3(0, 0, 0);
//...
}
Ray get_ray(int i, int j) const
{
Vector3 offset = sample_square();
//(i,j)번째 픽셀의 offset만큼 이동한 center좌표
Vector3 pixel_sample = pixel00_loc + (i + offset.x()) * pixel_delta_u + (j + offset.y()) * pixel_delta_v;
Point3 ray_origin = camera_center;
Vector3 ray_dir = pixel_sample - ray_origin;
return Ray(ray_origin, ray_dir);
}
Vector3 sample_square() const
{
return Vector3(random_double() - 0.5, random_double() - 0.5, 0);
}
//...
};
#endif
이걸 하면 다음과 같이 결과물이 바뀜

이랬던 픽셀의 테두리가

이렇게 자연스럽게 바뀜!