[RT in One Weekend Series 4] Rays, a Simple Camara, and Background (번역)

목차: Series 1: Index and Overview (Link)
이전 글: Series 3: The “vec3” Class (Link)
다음 글: Series 5: Adding a Sphere (Link)

Ray Tracer의 가장 기본은 Ray이다. 보통 모든 Ray Tracer은 Ray Class를 가진다. Ray Class는 Ray가 도달하는 위치의 최종 색상 값을 계산한다.

출처 1의 기사(Article)에서는 Ray를 p(t) = A + t*B 함수로 정의하였다. p는 3D Position(위치)을 의미하며, t는 Float Number를 의미한다. A는 Ray 시작 위치(Ray Origin)이며, B는 Ray의 방향(Ray Direction)을 의미한다. 만약 t 값이 1일 경우 p(1)= A + B가 된다. t 값이 2일 경우 p(2) = A + 2B가 된다. 그림 1은 p(2)의 예제를 보여준다.

그림 1: p(2)의 예제 그림 (출처 1)

MK: 여기서 Ray Origin (A)의 위치는 카메라의 위치인 듯 하다. Ray의 방향(Ray Direction)은 Ray Origin 위치에서 Background의 Pixel의 위치의 차이를 의미한다. Background Pixel에서 Ray Origin 위치를 뺀 다음 Unit Vector로 변경하면 방향 Vector가 생성된다. 해당 글에서는 Origin이 항상 (0, 0, 0)에 위치하기 때문에 빼기 연산을 수행하지 않아도 된다.

#ifndef MKRAY_H
#define MKRAY_H

#include "mkvec3.h"

class ray{
    public:
        ray(){}
        ray(const vec3 &a, const vec3 &b){
            A = a;
            B = b;
        }
        vec3 origin() const{
            return A;
        }
        vec3 direction() const{
            return B;
        }
        vec3 pointAtParameter(float t) const{
            //MK: Based on the article, B should be changed to unit vector. 
            //MK: However, input B is already set to unit vector when the input is defined,
            //MK: this function does not need to perform additional operation.
            return (A + t * B);
        }
    private:
        vec3 A;
        vec3 B;
};

#endif

위 코드는 p(t) 함수를 작성한 코드이다.

MK: 이번 글에서는 Ray의 pointAtParameter(…)함수를 사용하지 않는다. 추측하건대 우리가 보는 빚(Ray)는 계속 직진을 하기 때문에 A + t * B의 함수로 Ray 이동 경로를 정의한 듯 하다. 뒤에 글에서 나오지만, 특정 t 값에 Ray가 특정 Object(물체)와 Intersection 여부를 계산하게 된다. 추가로 B는 Unit Vector 형태여야 한다. 하지만, B를 Unit Vector로 변경하지 않았다. 아마 Ray를 생성하는 단계에서 Unit Vector로 Input을 정의하기 때문으로 추측한다.

Ray Tracer의 기본은 눈(Camera)에서 Ray를 보내서 해당 Ray가 도달하는 위치의 색상을 계산하는 것이다. Ray는 Intersection(교차) 등의 연산을 사용하여 최종 색상을 결정하게 된다.

정교한 Ray Tracer을 생성하기 이전에 Background를 표시하는 간단한 코드 부터 작성을 시작한다. 해당 글에서는 Right Hand Coordinate System을 기반으로 하기 때문에 Camera에서 보는 화면은 -Z 방향이다. 아래 코드는 흰색/파란색을 Linear Interpolation(lerp) 하여 Background 색상을 결정하는 코드이다.

#include <iostream>
#include <fstream>
#include "mkray.h"

using namespace std;

vec3 color(const ray &r){
    vec3 unitDirection = unit_vector(r.direction());
    float t = 0.5 * (unitDirection.y() + 1.0);
    vec3 ret = (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
    return ret;
}

int main(){
    int nx = 400;
    int ny = 200;
    string fileName = "Ch3.ppm";
    ofstream writeFile(fileName.data());
    if(writeFile.is_open()){
        writeFile.flush();
        writeFile << "P3\n" << nx << " " << ny << "\n255\n";
        vec3 lowerLeftCorner(-2.0, -1.0, -1.0);
        vec3 horizontal(4.0, 0.0, 0.0);
        vec3 vertical(0.0, 2.0, 0.0);
        vec3 origin(0.0, 0.0, 0.0);
        for(int j = ny - 1; j >= 0; j--){
            for(int i = 0; i < nx; i++){
                float u = float(i) / float(nx);
                float v = float(j) / float(ny);
                ray r(origin, (lowerLeftCorner + u * horizontal + v * vertical));
                vec3 col = color(r);
                int ir = int(255.99 * col[0]);
                int ig = int(255.99 * col[1]);
                int ib = int(255.99 * col[2]);
                writeFile << ir << " " << ig << " " << ib << "\n";
            }
        }
        writeFile.close();
    }
    return 0;
}

위 코드는 그림 2와 같이 색상 연산을 수행한다.

그림 2: Background 색상 계산 방법 (출처 1)

Ray가 도달하는 Y축의 값에 따라 파란색과 흰색을 적당히 합쳐서 색상을 결정한다. Y축 값이 증가할수록 파란색에 가까워지고 Y축 값이 아래로 향할수록 흰색에 가까운 색상을 가진다. Color 함수에서 Y축을 사용하여 T 값을 선택한다. T 값은 0~1 사이에 존재한다. 마지막으로 T 값을 사용하여 Interpolation 연산을 수행하면 최종 색상이 결정된다.

MK: 개인적으로 출처 1의 설명이 조금은 부족하다는 기분이 든다. 주어진 그림/글/코드를 토대로 개인적으로 다시 해석을 해보았다. Origin (0, 0, 0)에서 Ray를 모든 곳으로 보낸다. 우리는 이미지 400 x 200을 사용하기 때문에 총 80,000개의 Ray를 생성하여 (-2, 1, -1)부터 (2, -1, -1) 공간 사이에 아주 공정한 거리를 두어 Ray를 보낸다. 이렇게 보낸 Ray의 도달 위치에 따라 파란색과 흰색을 Interpolation 하여 최종 생상을 결정한다.

그림 3:  결과 이미지

그림 3은 위 코드를 실행하면 출력되는 결과이다.

출처

  1. http://www.realtimerendering.com/raytracing/Ray%20Tracing%20in%20a%20Weekend.pdf

2 thoughts on “[RT in One Weekend Series 4] Rays, a Simple Camara, and Background (번역)”

  1. 안녕하세요.
    유익한 글 올려주셔서 잘 읽고 있습니다.
    궁금한 점이 있어서 글 남깁니다.
    글에서 오른손 좌표계를 사용한다고 하셨는데 그림 2에서는 z 축의 방향이 반대로 되어있는 것 같아서요.
    스크린의 반대 방향 쪽이 -z 방향이 맞는 건가요?
    감사합니다.

    Reply
  2. 안녕하세요. 글 남겨주셔서 감사합니다.
    제가 그림을 잘못 그렸습니다..ㅠㅠ
    틀린 부분 알려주셔서 감사합니다.
    수정하도록 하겠습니다.
    감사합니다.

    Reply

Leave a Comment