Company
교육 철학
🖼️

2. Output an Image (이미지 출력)

2. Output an Image(이미지 출력)

2.1 The PPM Image Format(PPM 이미지 형식)

렌더러를 시작할 때마다 이미지를 볼 수 있는 방법이 필요합니다. 가장 간단한 방법은 파일에 작성하는 것입니다. 문제는 형식이 너무 많다는 것입니다. 그 중 많은 것들이 복잡합니다. 저는 항상 평문 ppm 파일로 시작합니다. 다음은 Wikipedia의 좋은 설명입니다:
*그림 1: PPM 예제*
이러한 것을 출력하는 C++ 코드를 만들어 봅시다:
#include <iostream> int main() { // Image int ImageWidth = 256; int ImageHeight = 256; // Render std::cout << "P3\n" << ImageWidth << ' ' << ImageHeight << "\n255\n"; for (int j = 0; j < ImageHeight; j++) { for (int i = 0; i < ImageWidth; i++) { auto r = double(i) / (ImageWidth - 1); auto g = double(j) / (ImageHeight - 1); auto b = 0.0; int ir = int(255.999 * r); int ig = int(255.999 * g); int ib = int(255.999 * b); std::cout << ir << ' ' << ig << ' ' << ib << '\n'; } } return 0; }
C++
복사
*리스트 1: [main.cc] 첫 번째 이미지 생성*
이 코드에서 주목해야 할 몇 가지 사항이 있습니다:
1.
픽셀은 행 단위로 작성됩니다.
2.
각 픽셀 행은 왼쪽에서 오른쪽으로 작성됩니다.
3.
이러한 행들은 위에서 아래로 작성됩니다.
4.
관례적으로 각 빨강/녹색/파랑 구성 요소는 내부적으로 0.0에서 1.0 범위의 실수 값 변수로 표현됩니다. 이들을 출력하기 전에 0에서 255 사이의 정수 값으로 스케일링해야 합니다.
5.
빨강은 왼쪽에서 오른쪽으로 완전히 꺼진 상태(검정)에서 완전히 켜진 상태(밝은 빨강)로 변하고, 녹색은 위쪽에서 완전히 꺼진 상태(검정)에서 아래쪽에서 완전히 켜진 상태(밝은 녹색)로 변합니다. 빨강과 녹색 빛을 함께 더하면 노란색이 되므로 오른쪽 아래 모서리는 노란색이어야 합니다.

2.2 Creating an Image File(이미지 파일 생성)

파일이 표준 출력 스트림에 작성되기 때문에 이를 이미지 파일로 리디렉션해야 합니다. 일반적으로 이는 명령줄에서 리디렉션 연산자를 사용하여 수행됩니다.
우리는 기존 레이트레이싱 환경과 다르게 window환경에서 visual studio community IDE 를 이용하여 빌드할 예정입니다. 이예제가 작성된 시점에는 2022 버전을 사용 하였고 추후 2026이 쿠다 커널을 지원해줄때 언제든지 마이그레이션을 진행해도 좋습니다.
그런 다음 새로 빌드한 프로그램을 다음과 같이 실행합니다: 이는 이미지 뷰어로 볼수 있는 ppm 파일로 바꿔줍니다.
build\Debug\inOneWeekend.exe > image.ppm
Plain Text
복사
Mac 또는 Linux에서 릴리스 빌드는 다음과 같이 프로그램을 실행합니다:
build/inOneWeekend > image.ppm
Plain Text
복사
완전한 빌드 및 실행 지침은 프로젝트 README에서 찾을 수 있습니다.
출력 파일을 열면(제 Mac에서는 ToyViewer를 사용하지만, 여러분이 좋아하는 이미지 뷰어에서 시도해보시고 뷰어가 지원하지 않으면 "ppm viewer"를 구글에서 검색하세요) 다음과 같은 결과가 표시됩니다:
*그림 1: 첫 번째 PPM 이미지*
만세! 이것은 그래픽의 "hello world"입니다. 이미지가 이렇게 보이지 않는다면, 출력 파일을 텍스트 에디터에서 열어서 어떻게 보이는지 확인하세요. 다음과 같이 시작해야 합니다:
P3 256 256 255 0 0 0 1 0 0 2 0 0 3 0 0 4 0 0 5 0 0 6 0 0 7 0 0 8 0 0 9 0 0 10 0 0 11 0 0 12 0 0 ...
Plain Text
복사
*리스트 2: 첫 번째 이미지 출력*
PPM 파일이 이렇게 보이지 않는다면, 포맷팅 코드를 다시 확인하세요. 이렇게 보이지만 렌더링에 실패한다면, 이미지 뷰어를 혼란스럽게 하는 줄 끝 차이나 비슷한 문제가 있을 수 있습니다. 이를 디버그하는 데 도움이 되도록 Github 프로젝트의 images 디렉토리에서 test.ppm 파일을 찾을 수 있습니다. 이는 뷰어가 PPM 형식을 처리할 수 있는지 확인하고 생성된 PPM 파일과 비교하는 데 도움이 될 것입니다.
일부 독자들은 Windows에서 생성된 파일을 보는 데 문제가 있다고 보고했습니다. 이 경우 문제는 종종 PPM이 UTF-16으로 작성되는 것이며, 종종 PowerShell에서 발생합니다. 이 문제가 발생하면 이 문제에 대한 도움말을 보려면 Discussion 1114를 참조하세요.
모든 것이 올바르게 표시된다면, 시스템 및 IDE 문제는 거의 완료된 것입니다. 이 시리즈의 나머지 부분은 생성된 렌더링 이미지에 대해 동일한 간단한 메커니즘을 사용합니다.
다른 이미지 형식을 생성하려면 stb_image.h를 추천합니다. 이는 GitHub에서 사용 가능한 헤더 전용 이미지 라이브러리입니다.

2.3 Adding a Progress Indicator(진행 표시기 추가)

계속하기 전에 출력에 진행 표시기를 추가해봅시다. 이것은 긴 렌더링의 진행 상황을 추적하고 무한 루프나 다른 문제로 인해 멈춘 실행을 식별하는 편리한 방법입니다.
우리 프로그램은 표준 출력 스트림(std::cout)에 이미지를 출력하므로 이것은 그대로 두고 대신 로깅 출력 스트림(std::clog)에 작성합니다:
for (int j = 0; j < ImageHeight; ++j) { std::clog << "\rScanlines remaining: " << (ImageHeight - j) << ' ' << std::flush; for (int i = 0; i < ImageWidth; i++) { auto r = double(i) / (ImageWidth - 1); auto g = double(j) / (ImageHeight - 1); auto b = 0.0; int ir = int(255.999 * r); int ig = int(255.999 * g); int ib = int(255.999 * b); std::cout << ir << ' ' << ig << ' ' << ib << '\n'; } } std::clog << "\rDone. \n";
C++
복사
*리스트 3: [main.cc] 진행 보고 기능이 있는 메인 렌더 루프*
이제 실행하면 남은 스캔라인 수의 실행 카운트가 표시됩니다. 너무 빨리 실행되어 보이지 않을 수도 있습니다! 걱정하지 마세요 — 레이 트레이서를 확장하면서 천천히 업데이트되는 진행 표시줄을 볼 시간이 많을 것입니다.