
해당 포스팅은 "RayTracingInOneWeek"을 보고 학습한 내용입니다.
MAC OS M1 버전입니당.
윈도우는 저도 몰라요 ^_^
컴퓨터에서 물체를 렌더링할 때, 빛을 구현하는 방법에는 여러 가지 방법이 있다.
그 중에서 Ray Tracing은 "광원(Ray)"으로부터 시작하여 물체에 반사되어 "스크린"에 도달하는 빛을 역추적(Trace)하여 계산하는 방식이다.
즉, 계산량이 엄청 엄청 많다...
(참고로 엔비디아의 유명한 그래픽 카드인 "RTX XXXX" 에서 RT가 raytracing의 약자라고 한다. 첨 알았당..)
어쨌든 이 RayTracing 기법을 c++로 구현을 해보려고 한다.!
ppm이란 ? "portable pixmap"의 약자이다.
3개의 Header 정보와 pixel 정보를 입력하면 이미지를 생성해준다!
ppm은 3개의 header 정보를 가진다.
- P3: 매직 넘버 (standard 값으로 P3는 ASCII 코드 값을 의미한다.)
- 256 256: 이미지의 가로, 세로 사이즈
- 255: pixel의 max값 (몇bit 사이즈를 만들것인지 정해준다.)
pixel 값은 R,G,B 값 (0~255)을 정해주면 된다.
따라서 이 ppm을 만드는 코드를 작성해보자.
그러나! 예제를 보니 cmake로 빌드 파일을 만들어 작업하셨다고 한다.
똑같이 따라해보자..!
먼저, homebrew를 통해 cmake를 설치해준다.
> brew install cmake
설치가 완료되면, 설치가 잘 되었는지 version을 확인해준다.
> cmake --version

이제, 본격적으로 코드를 작성해보자.
vscode를 사용하여 c++ 파일을 작성하였다.
(포스팅한 교수님은 확장자를 cc를 사용하셨지만, 찾아보니 Unix/Linux 에선 cc 확장자를 사용하는게 좋고, Xcode나 윈도우는 cpp 파일을 작성하는게 좋다고 한다. 그래서 걍 익숙한 cpp로 만들었다)
#include <iostream>
using namespace std;
int main() {
// Image
int image_width = 256;
int image_height = 256;
// Render
cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j = 0; j < image_height; ++j) {
for (int i = 0; i < image_width; ++i) {
auto r = double(i) / (image_width-1);
auto g = double(j) / (image_height-1);
auto b = 0;
int ir = static_cast<int>(255.999 * r);
int ig = static_cast<int>(255.999 * g);
int ib = static_cast<int>(255.999 * b);
cout << ir << ' ' << ig << ' ' << ib << '\n';
}
}
}
ppm 작성 코드는 몇가지 주의점이 있다.
이 코드로 한번 실행을 시켜보자.

위와 같이 출력되면 된거다.
이 코드를 ppm 이미지 파일로 만들어 보자.
c++ 파일과 같은 경로에 CMakeLists.txt 파일을 만들어 줬다.
그리고 build 폴더도 만들어 줬다.

CMakeLists.txt 파일은 다음과 같이 작성해주었다.
CMAKE_MINIMUM_REQUIRED(VERSION 3.27)
project(project01)
add_executable(project01 project01.cpp)
위 버전은 설치된 버전에 맞게 입력해주면 된다.
그리고 ppm 확장자를 이미지로 만들어 주기 위해서
vscode에서 ppm viewer 를 설치해 주었다.

본격적으로 실행하여 ppm 파일을 만들어보자.
💬 먼저, cmake를 사용하여 빌드 파일을 만들어 주었다.
동일 디렉토리에 만들면, 복잡하기 때문에 build 폴더에 cmake를 실행해주었다.
> cd build
> cmake ..
> make

warning 문구는 c++11 버전 문제이므로 일단은 넘어가주었다..ㅎㅎ
어쨌든 build 폴더에 Makefile 이 있으면 성공이다.

💬 여기서 다시 상위 폴더로 넘어가서
build 폴더에 있는 실행 파일을 ppm 이미지 파일로 만들어 주었다.
> cd ..
> ./build/[실행파일명] > proj.ppm

💬 그러면 해당 디렉토리에 ppm 파일이 생기고..!
클릭하면 이미지 파일을 확인할 수 있다.
짠, 이게 그래픽의 "hello world" 이자 시발점 이다.

이제, 출력하는 데 필요한 Progress Indicator를 추가해보자.
Progress Indicator는
지금은 표준 입력 스트림인 (std::cout)을 사용하고 있지만,
그대로 두고, 로깅 출력 스트림 (std::clog) 를 사용하고자 한다.
clog는 기본적으로 cout과 동일하게 콘솔에 출력하지만, 로그를 구분해준다.
그래서 for loop 안에 남은 scanlines를 확인할 수 있는 코드를 넣어줬다.
for (int j = 0; j < image_height; ++j) {
//로깅 출력 스트림
clog << "\nScanlines remaining: " << (image_height -j) << ' ' << flush;
for (int i = 0; i < image_width; ++i) {
auto r = double(i) / (image_width-1);
auto g = double(j) / (image_height-1);
auto b = 0;
int ir = static_cast<int>(255.999 * r);
int ig = static_cast<int>(255.999 * g);
int ib = static_cast<int>(255.999 * b);
cout << ir << ' ' << ig << ' ' << ib << '\n';
}
}
clog << "\rDone. \n";
실행 결과는 다음과 같다.

지금은 실행되는 count가 작아서
호다닥 실행되느라 진행률이 잘 안보이지만, 나중에 Raytracer를
확장해 나아감에 따라 천천히 업데이트 되는 것을 볼 수 있다고 한다!
글 잘 봤습니다.