[42cursurs]Ray Tracing in One Weekend 2-vector

이상헌·2020년 9월 29일
1
post-thumbnail

지금부터 나올 내용은 기하에서의 벡터를 알고 있다면 이해가 쉽다. 이외에도 내적, 외적, 구의 방정식 등 기하 벡터를 공부해보지 않은 분들은 낯설 수 있다.

Vector class

vec3.h - vecto class

#ifndef VEC3_H
#define VEC3_H

#include <cmath>
#include <iostream>

using std::sqrt;

class vec3 {
    public:
    // vec3의 생성자다. 
    // vec3 생성 시 매개변수의 값이 없으면 x, y, z가 0인 vec3 반환
    // 매개변수의 값이 있다면 (e0, e1, e1)인 vec3를 반환한다.
        vec3() : e{0,0,0} {}
        vec3(double e0, double e1, double e2) : e{e0, e1, e2} {}

	// 각 좌표의 값을 반환하는 함수
        double x() const { return e[0]; }
        double y() const { return e[1]; }
        double z() const { return e[2]; }
        
	// vec3 class 연산자 오버로딩 
   	// vec3 instance에 대한 -, [], += 등의 연산자의 동작을 정의한다.
        vec3 operator-() const { return vec3(-e[0], -e[1], -e[2]); }
        double operator[](int i) const { return e[i]; }
        double& operator[](int i) { return e[i]; }

        vec3& operator+=(const vec3 &v) {
            e[0] += v.e[0];
            e[1] += v.e[1];
            e[2] += v.e[2];
            return *this;
        }

        vec3& operator*=(const double t) {
            e[0] *= t;
            e[1] *= t;
            e[2] *= t;
            return *this;
        }

        vec3& operator/=(const double t) {
            return *this *= 1/t;
        }

	// 벡터의 길이(크기)를 반환한다.
        double length() const {
            return sqrt(length_squared());
        }
        
        // 벡터 크기의 제곱 값을 반환한다.
        double length_squared() const {
            return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
        }

    public:
    	//벡터의 x, y, z 값을 담을 배열이다.
        double e[3];
};

// Type aliases for vec3
using point3 = vec3;   // 3D point
using color = vec3;    // RGB color

#endif

vector class다. 더불어 rgb 값을 표현하는 color와 3차원 좌표계의 점을 나타내는 point3를 함께 alias(이하 별칭)로 선언해준다. 별칭을 써서 vec3와 point, color를 구분해준다. vec3와 동작이 같지만 쓰임새에 따라 별칭을 써서 코드에서 구분하고 이해하기 수월하다.

vec3.h - Utility Functions

// vec3 Utility Functions

inline std::ostream& operator<<(std::ostream &out, const vec3 &v) {
    return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
}

inline vec3 operator+(const vec3 &u, const vec3 &v) {
    return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
}

inline vec3 operator-(const vec3 &u, const vec3 &v) {
    return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
}

inline vec3 operator*(const vec3 &u, const vec3 &v) {
    return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
}

inline vec3 operator*(double t, const vec3 &v) {
    return vec3(t*v.e[0], t*v.e[1], t*v.e[2]);
}

inline vec3 operator*(const vec3 &v, double t) {
    return t * v;
}

inline vec3 operator/(vec3 v, double t) {
    return (1/t) * v;
}

// vector 내적(dot product) 함수
inline double dot(const vec3 &u, const vec3 &v) {
    return u.e[0] * v.e[0]
         + u.e[1] * v.e[1]
         + u.e[2] * v.e[2];
}

// vector 외적(cross product) 함수
inline vec3 cross(const vec3 &u, const vec3 &v) {
    return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
                u.e[2] * v.e[0] - u.e[0] * v.e[2],
                u.e[0] * v.e[1] - u.e[1] * v.e[0]);
}

// 단위 혹은 방향 벡터 반환 함수
inline vec3 unit_vector(vec3 v) {
    return v / v.length();
}

위의 코드는 vec3.h에 포함되는 코드로 vec3 객체의 사칙연산자 오버로딩과 자주 쓰일 기타 연산의 구현이다.

color.h - color utility

#ifndef COLOR_H
#define COLOR_H

#include "vec3.h"

#include <iostream>

void write_color(std::ostream &out, color pixel_color) {
// color를 받아 대응하는 rgb값을 출력하는 함수다.
    // Write the translated [0,255] value of each color component.
    out << static_cast<int>(255.999 * pixel_color.x()) << ' '
        << static_cast<int>(255.999 * pixel_color.y()) << ' '
        << static_cast<int>(255.999 * pixel_color.z()) << '\n';
}

#endif

관습적으로 rgb값을 0과 1 사이의 값으로 다룬다고 했다. write_color는 이렇게 쓰인 값을 다시 대응되는 rgb값으로 출력하는 함수로 구현한 것이다.

main.cc

	// color.h, vec3.h 헤더 추가
    #include "color.h"
    #include "vec3.h"

    #include <iostream>

    int main() {

        // Image

        const int image_width = 256;
        const int image_height = 256;

        // 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) {
            	// 출력할 픽셀의 위치에 따라 rgb 값을 결정
                color pixel_color(double(i)/(image_width-1), double(j)/(image_height-1), 0.25);
                // 픽셀의 rgb값 write_color로 출력
                write_color(std::cout, pixel_color);
            }
        }

        std::cerr << "\nDone.\n";
    }

이번 시간에 작성한 코드를 적용한 main 소스 파일이다. 원문에서 코드 블럭이 하이라이트된 코드가 변경된 부분이다.

profile
배고픈 개발자 sayi입니다!

0개의 댓글