[RT in One Weekend Series 3] The “vec3” Class (번역)

목차: Series 1: Index and Overview (Link)
이전 글: Series 2: Output an Image (Link)
다음 글: Series 4: Rays, a Simple Camara, and Background (Link)

이번 글에서는 효율적으로 Vector 연산을 수행하기 위해서 한개의 Vector Class와 여러개의 Vector Operator 함수를 작성한다. 그래픽 연산에서는 4D Vector를 아주 많이 사용한다. 예를 들어 좌표를 나타내기 위해서 4D (3D + Homogeneous Coordinate)를 사용한다 (출처 2). 이와 더불어 색상의 값을 나타내기 위해서 4D Vector (Red, Green, Blue, Alpha)을 사용한다. 그래서 이미지를 그리기전에 Vector 관련 함수를 먼저 구현한다. 이번 글은 큰 내용은 없으며 아래 Vector 코드를 작성하면 된다.

#MK: Vector Class
#ifndef MKVEC3_H
#define MKVEC3_H

#include <math.h>
#include <stdlib.h>
#include <iostream>

class vec3{
    public:
      vec3(){}
      vec3(float e0, float e1, float e2){
        element[0] = e0;
        element[1] = e1;
        element[2] = e2;
      }

      inline float x() const{ return element[0];}
      inline float y() const{ return element[1];}
      inline float z() const{ return element[2];}

      inline float r() const{ return element[0];}
      inline float g() const{ return element[1];}
      inline float b() const{ return element[2];}

      inline const vec3& operator+() const{ return *this;}
      inline vec3 operator-() const {return vec3(-element[0], -element[1], -element[2]);}
      inline float operator[] (int i) const {return element[i];}
      inline float &operator[] (int i) {return element[i];}

      inline vec3& operator+=(const vec3 &v){
          element[0] += v.element[0];
          element[1] += v.element[1];
          element[2] += v.element[2];
          return *this;
      }
      inline vec3& operator-=(const vec3 &v){
          element[0] -= v.element[0];
          element[1] -= v.element[1];
          element[2] -= v.element[2];
          return *this;
      }
      inline vec3& operator*=(const vec3 &v){
          element[0] *= v.element[0];
          element[1] *= v.element[1];
          element[2] *= v.element[2];
          return *this;
      }
      inline vec3& operator/=(const vec3 &v){
          element[0] /= v.element[0];
          element[1] /= v.element[1];
          element[2] /= v.element[2];
          return *this;
      }
      inline vec3& operator*=(const float t){
          element[0] *= t;
          element[1] *= t;
          element[2] *= t;
          return *this;
      }
      inline vec3& operator/=(const float t){
          float k = 1.0/t;
          element[0] *= k;
          element[1] *= k;
          element[2] *= k;
          return *this;
      }

      inline float length() const{
          return sqrt(element[0] * element[0] + element[1] * element[1] + element[2] * element[2]);
      }
      inline float squared_length() const{
          return (element[0] * element[0] + element[1] * element[1] + element[2] * element[2]);
      }
      inline void make_unit_vector(){
          float k = 1.0 / (sqrt(element[0] * element[0] + element[1] * element[1] + element[2] * element[2]));
          element[0] *= k;
          element[1] *= k;
          element[2] *= k;
      };

      float element[3];
};

inline std::istream& operator>>(std::istream &is, vec3 &t){
    is >> t.element[0] >> t.element[1] >> t.element[2];
    return is;
}

inline std::ostream& operator<<(std::ostream &os, const vec3 &t){
    os << t.element[0] << t.element[1] << t.element[2];
    return os;
}

inline vec3 operator+(const vec3 &v1, const vec3 &v2){
    return vec3(v1.element[0] + v2.element[0], v1.element[1] + v2.element[1], v1.element[2] + v2.element[2]);
}

inline vec3 operator-(const vec3 &v1, const vec3 &v2){
    return vec3(v1.element[0] - v2.element[0], v1.element[1] - v2.element[1], v1.element[2] - v2.element[2]);
}

inline vec3 operator*(const vec3 &v1, const vec3 &v2){
    return vec3(v1.element[0] * v2.element[0], v1.element[1] * v2.element[1], v1.element[2] * v2.element[2]);
}

inline vec3 operator/(const vec3 &v1, const vec3 &v2){
    return vec3(v1.element[0] / v2.element[0], v1.element[1] / v2.element[1], v1.element[2] / v2.element[2]);
}

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

inline vec3 operator/(const vec3 &v, const float t){
    return vec3(v.element[0]/t, v.element[1]/t, v.element[2]/t);
}

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

inline float dot(const vec3 &v1, const vec3 &v2){
    return (v1.element[0] * v2.element[0] + v1.element[1] * v2.element[1] + v1.element[2] * v2.element[2]);
}

inline vec3 cross(const vec3 &v1, const vec3 &v2){
    return vec3(
                (v1.element[1] * v2.element[2] - v1.element[2] * v2.element[1]),
                -(v1.element[0] * v2.element[2] - v1.element[2] * v2.element[0]),
                (v1.element[0] * v2.element[1] - v1.element[1] * v2.element[0])
            );
}

inline vec3 unit_vector(vec3 v){
    return (v/v.length());
}

#endif

#MK: Main (Minor change)
#include <iostream>
#include <fstream>
#include "mkvec3.h"

using namespace std;

int main(){
    int nx = 400;
    int ny = 200;
    string fileName = "Ch2.ppm";
    ofstream writeFile(fileName.data());
    if(writeFile.is_open()){
        writeFile.flush();
        writeFile << "P3\n" << nx << " " << ny << "\n255\n";
        for(int j = ny - 1; j >= 0; j--){
            for(int i = 0; i < nx; i++){
                vec3 col(float(i)/float(nx), float(j)/float(ny), 0.2);
                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;
}

코드를 작성하였으며 컴파일되는 것까지 확인했다. 중간중간 버그가 존재할 수도 있다. 계속 강의를 읽으면서 버그를 찾게 되면 수정할 계획이다.

출처

  1. http://www.realtimerendering.com/raytracing/Ray%20Tracing%20in%20a%20Weekend.pdf
  2. http://blog.daum.net/shksjy/229

Leave a Comment