Search

The vec3 Class

Created
2021/03/24
Tags
Chapter 3
대부분의 그래픽 프로그램에는 기하학적 Vector색상을 저장하기 위한 몇 Class들이 존재한다. 많은 시스템에서는 이러한 기하학적 Vector색상을 위한 Class4D로 표현한다. 기하학적 Vector의 경우 기하학의 3D동차좌표 (Homogeneous Coordinate), 색상을 위한 ClassRGB색상을 위한 투명도 (Alpha Transparency Channel)로 구성된다.
하지만 강의에서 진행되는 좌표에 대해서 3개면 충분하다. 따라서 색상, 위치, 방향, 기준 등을 표현하는데 있어서 vec3를 사용한다. 몇 사람들은 vec3를 이용하는 것에 대해 색상에 위치를 더하는 바보 같은 행동을 막을 수 없기 때문에 선호하지 않기도 하지만, 코드 작성의 의도에 있어서 틀리지 않음을 가정하고 강의 진행에 있어서 적은 코드 작성하기 위해 vec3를 이용한다.
그래도 헷갈리지 않기 위해 vec3 Classpoint3color라고 별칭을 두고 진행을 한다. 말 그대로 별칭일 뿐이므로 colorpoint3를 연산하더라도 별다른 경고를 주지 않기 때문에 주의해야 한다. 단순히 의도와 용도를 명확히 하기 위해서만 사용한다고 보면 된다.

1. vec3 Utility Functions

vec3.hHeader는 아래와 같다. 비록 double을 이용하긴 했지만, 대체적으로 RT에서는 float을 많이 이용한다는 점을 유념해두자. 지금은 어떤 타입으로 두어도 무방하다.
#ifndef VEC3_H # define VEC3_H # include <cmath> # include <iostream> using std::sqrt; class vec3 { public: 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 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: double e[3]; }; // Type aliases for vec3 using point3 = vec3; // 3D point using color = vec3; // RGB color // 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; } 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]; } 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(); } #endif
C++

2. Color Utility Functions

color에 대해 정의한 color.h라는 Header는 아래와 같다.
#ifndef COLOR_H # define COLOR_H # include "vec3.h" # include <iostream> void write_color(std::ostream &out, color pixel_color) { // 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
C++

3. Change the Code on main.cpp

Chapter 2에서 작성했던 main.cpp 파일을 아래와 같이 수정하면 된다.
#include "vec3.h" #include "color.h" int main(void) { // 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) { color pixel_color(double(i) / (image_width - 1), double(j) / (image_height - 1), 0.25); write_color(std::cout, pixel_color); } } std::cerr << "\nDone.\n"; return (0); }
C++
Chapter 2에서 했던 것과 마찬가지로 Image File을 만들어보면 동일한 결과가 나오는 것을 확인할 수 있다.